Merge branch 'main' into feature/admin-search-experiment

This commit is contained in:
Martin Brennan
2025-02-13 12:37:47 +10:00
234 changed files with 5557 additions and 3769 deletions

View File

@@ -3,7 +3,7 @@ name: Pnpm dedupe on Dependabot PRs
on:
push:
branches:
- "dependabot/npm_and_yarn/*"
- "dependabot/npm_and_yarn/**/*"
paths:
- "pnpm-lock.yaml"
@@ -31,9 +31,9 @@ jobs:
node-version: 22
- name: pnpm install
run: pnpm install --frozen-lockfile
run: pnpm install --ignore-scripts --frozen-lockfile
- run: pnpm dedupe
- run: pnpm dedupe --ignore-scripts
- name: Git push
run: |

View File

@@ -87,7 +87,7 @@ GEM
bootsnap (1.18.4)
msgpack (~> 1.2)
builder (3.3.0)
bullet (8.0.0)
bullet (8.0.1)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
byebug (11.1.3)
@@ -199,7 +199,7 @@ GEM
reline (>= 0.4.2)
iso8601 (0.13.0)
jmespath (1.6.2)
json (2.9.1)
json (2.10.1)
json-schema (5.1.1)
addressable (~> 2.8)
bigdecimal (~> 3.1)
@@ -258,21 +258,21 @@ GEM
minitest (5.25.4)
mocha (2.7.1)
ruby2_keywords (>= 0.0.5)
msgpack (1.7.5)
msgpack (1.8.0)
multi_json (1.15.0)
multi_xml (0.7.1)
bigdecimal (~> 3.1)
mustache (1.1.1)
net-http (0.6.0)
uri
net-imap (0.5.5)
net-imap (0.5.6)
date
net-protocol
net-pop (0.1.2)
net-protocol
net-protocol (0.2.2)
timeout
net-smtp (0.5.0)
net-smtp (0.5.1)
net-protocol
nio4r (2.7.4)
nokogiri (1.18.2-aarch64-linux-gnu)
@@ -298,19 +298,20 @@ GEM
oj (3.16.9)
bigdecimal (>= 3.0)
ostruct (>= 0.2)
omniauth (1.9.2)
omniauth (2.1.2)
hashie (>= 3.4.6)
rack (>= 1.6.2, < 3)
rack (>= 2.2.3)
rack-protection
omniauth-facebook (9.0.0)
omniauth-oauth2 (~> 1.2)
omniauth-github (1.4.0)
omniauth (~> 1.5)
omniauth-oauth2 (>= 1.4.0, < 2.0)
omniauth-google-oauth2 (0.8.2)
omniauth-github (2.0.0)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.7.1)
omniauth-google-oauth2 (1.0.1)
jwt (>= 2.0)
oauth2 (~> 1.1)
omniauth (~> 1.1)
omniauth-oauth2 (>= 1.6)
omniauth (~> 2.0)
omniauth-oauth2 (~> 1.7.1)
omniauth-oauth (1.2.1)
oauth
omniauth (>= 1.0, < 3)
@@ -329,7 +330,7 @@ GEM
parallel (1.26.3)
parallel_tests (4.9.0)
parallel
parser (3.3.7.0)
parser (3.3.7.1)
ast (~> 2.4.1)
racc
pg (1.5.9)
@@ -356,7 +357,7 @@ GEM
puma (6.6.0)
nio4r (~> 2.0)
racc (1.8.1)
rack (2.2.10)
rack (2.2.11)
rack-mini-profiler (3.3.1)
rack (>= 1.2.0)
rack-protection (3.2.0)
@@ -402,7 +403,7 @@ GEM
msgpack (>= 0.4.3)
optimist (>= 3.0.0)
rchardet (1.9.0)
rdoc (6.11.0)
rdoc (6.12.0)
psych (>= 4.0.0)
redcarpet (3.6.0)
redis (4.8.1)
@@ -427,7 +428,7 @@ GEM
rspec-core (~> 3.13.0)
rspec-expectations (~> 3.13.0)
rspec-mocks (~> 3.13.0)
rspec-core (3.13.2)
rspec-core (3.13.3)
rspec-support (~> 3.13.0)
rspec-expectations (3.13.3)
diff-lcs (>= 1.2.0, < 2.0)
@@ -440,7 +441,7 @@ GEM
rspec-support (~> 3.13.0)
rspec-multi-mock (0.3.1)
rspec (>= 3.7.0)
rspec-rails (7.1.0)
rspec-rails (7.1.1)
actionpack (>= 7.0)
activesupport (>= 7.0)
railties (>= 7.0)
@@ -458,7 +459,7 @@ GEM
rspec-core (>= 2.14)
rtlcss (0.2.1)
mini_racer (>= 0.6.3)
rubocop (1.71.1)
rubocop (1.71.2)
json (~> 2.3)
language_server-protocol (>= 3.17.0)
parallel (~> 1.10)
@@ -579,7 +580,7 @@ GEM
web-push (3.0.1)
jwt (~> 2.0)
openssl (~> 3.0)
webmock (3.24.0)
webmock (3.25.0)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)

View File

@@ -1,6 +1,8 @@
<UppyImageUploader
@imageUrl={{this.value}}
@placeholderUrl={{this.setting.placeholder}}
@onUploadDone={{fn (mut this.value)}}
@onUploadDeleted={{fn (mut this.value) null}}
@additionalParams={{hash for_site_setting=true}}
@type="site_setting"
@id={{concat "site-setting-image-uploader-" this.setting.setting}}

View File

@@ -1,7 +1,9 @@
import Group from "discourse/models/group";
import { service } from "@ember/service";
import DiscourseRoute from "discourse/routes/discourse";
export default class AdminUserIndexRoute extends DiscourseRoute {
@service site;
model() {
return this.modelFor("adminUser");
}
@@ -10,19 +12,10 @@ export default class AdminUserIndexRoute extends DiscourseRoute {
return this.currentModel.username;
}
afterModel(model) {
if (this.currentUser.admin) {
return Group.findAll().then((groups) => {
this._availableGroups = groups.filterBy("automatic", false);
return model;
});
}
}
setupController(controller, model) {
controller.setProperties({
originalPrimaryGroupId: model.primary_group_id,
availableGroups: this._availableGroups,
availableGroups: this.site.groups.filter((g) => !g.automatic),
customGroupIdsBuffer: model.customGroups.mapBy("id"),
ssoExternalEmail: null,
ssoLastPayload: null,

View File

@@ -14,7 +14,7 @@
"start": "ember serve"
},
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"@ember/string": "^4.0.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.3.0",
@@ -28,7 +28,7 @@
"@types/qunit": "^2.19.12",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@@ -149,7 +149,6 @@ class Setup {
discourse.limitedSiteSettings = {
secureUploads: siteSettings.secure_uploads,
enableDiffhtmlPreview: siteSettings.enable_diffhtml_preview,
traditionalMarkdownLinebreaks:
siteSettings.traditional_markdown_linebreaks,
enableMarkdownLinkify: siteSettings.enable_markdown_linkify,

View File

@@ -8,7 +8,7 @@
"ember-addon"
],
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"deprecation-silencer": "workspace:1.0.0",
"discourse-hbr": "workspace:1.0.0",
"discourse-widget-hbs": "workspace:1.0.0",
@@ -18,7 +18,7 @@
"ember-this-fallback": "^0.4.0"
},
"devDependencies": {
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"webpack": "^5.97.1"
},
"engines": {

View File

@@ -14,7 +14,7 @@
"start": "ember serve"
},
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"ember-auto-import": "^2.10.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.3.0",
@@ -26,7 +26,7 @@
"@glimmer/component": "^1.1.2",
"@glimmer/syntax": "0.93.1",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@@ -37,6 +37,7 @@ export default class AboutPage extends Component {
{
class: "members",
icon: "users",
display: true,
text: i18n("about.member_count", {
count: this.args.model.stats.users_count,
formatted_number: I18n.toNumber(this.args.model.stats.users_count, {
@@ -47,6 +48,7 @@ export default class AboutPage extends Component {
{
class: "admins",
icon: "shield-halved",
display: this.adminsCount > 0,
text: i18n("about.admin_count", {
count: this.adminsCount,
formatted_number: I18n.toNumber(this.adminsCount, { precision: 0 }),
@@ -55,6 +57,7 @@ export default class AboutPage extends Component {
{
class: "moderators",
icon: "shield-halved",
display: this.moderatorsCount > 0,
text: i18n("about.moderator_count", {
count: this.moderatorsCount,
formatted_number: I18n.toNumber(this.moderatorsCount, {
@@ -65,6 +68,7 @@ export default class AboutPage extends Component {
{
class: "site-creation-date",
icon: "calendar-days",
display: true,
text: this.siteAgeString,
},
];
@@ -253,10 +257,12 @@ export default class AboutPage extends Component {
<div class="about__left-side">
<div class="about__stats">
{{#each this.stats as |stat|}}
<span class="about__stats-item {{stat.class}}">
{{icon stat.icon}}
<span>{{stat.text}}</span>
</span>
{{#if stat.display}}
<span class="about__stats-item {{stat.class}}">
{{icon stat.icon}}
<span>{{stat.text}}</span>
</span>
{{/if}}
{{/each}}
</div>

View File

@@ -456,8 +456,8 @@ export default class ComposerEditor extends Component {
$preview.scrollTop(desired + 50);
}
_renderMentions(preview, unseen) {
unseen ||= linkSeenMentions(preview, this.siteSettings);
_renderMentions(preview) {
const unseen = linkSeenMentions(preview, this.siteSettings);
if (unseen.length > 0) {
this._renderUnseenMentions(preview, unseen);
} else {
@@ -480,9 +480,9 @@ export default class ComposerEditor extends Component {
});
}
_renderHashtags(preview, unseen) {
_renderHashtags(preview) {
const context = this.site.hashtag_configurations["topic-composer"];
unseen ||= linkSeenHashtagsInContext(context, preview);
const unseen = linkSeenHashtagsInContext(context, preview);
if (unseen.length > 0) {
this._renderUnseenHashtags(preview, unseen, context);
}
@@ -896,15 +896,13 @@ export default class ComposerEditor extends Component {
}
@action
previewUpdated(preview, unseenMentions, unseenHashtags) {
this._renderMentions(preview, unseenMentions);
this._renderHashtags(preview, unseenHashtags);
previewUpdated(preview) {
this._renderMentions(preview);
this._renderHashtags(preview);
this._refreshOneboxes(preview);
this._expandShortUrls(preview);
if (!this.siteSettings.enable_diffhtml_preview) {
this._decorateCookedElement(preview);
}
this._decorateCookedElement(preview);
this.composer.afterRefresh(preview);
}

View File

@@ -75,9 +75,7 @@
class="d-editor-preview-wrapper {{if this.forcePreview 'force-preview'}}"
>
<div class="d-editor-preview">
{{#unless this.siteSettings.enable_diffhtml_preview}}
{{html-safe this.preview}}
{{/unless}}
{{html-safe this.preview}}
</div>
<span class="d-editor-plugin">
<PluginOutlet

View File

@@ -8,12 +8,10 @@ import { classNames } from "@ember-decorators/component";
import { observes, on } from "@ember-decorators/object";
import { emojiSearch, isSkinTonableEmoji } from "pretty-text/emoji";
import { translations } from "pretty-text/emoji/data";
import { resolveCachedShortUrls } from "pretty-text/upload-short-url";
import { Promise } from "rsvp";
import TextareaEditor from "discourse/components/composer/textarea-editor";
import EmojiPickerDetached from "discourse/components/emoji-picker/detached";
import InsertHyperlink from "discourse/components/modal/insert-hyperlink";
import { ajax } from "discourse/lib/ajax";
import { SKIP } from "discourse/lib/autocomplete";
import Toolbar from "discourse/lib/composer/toolbar";
import discourseDebounce from "discourse/lib/debounce";
@@ -22,11 +20,8 @@ import deprecated from "discourse/lib/deprecated";
import { isTesting } from "discourse/lib/environment";
import { getRegister } from "discourse/lib/get-owner";
import { hashtagAutocompleteOptions } from "discourse/lib/hashtag-autocomplete";
import { linkSeenHashtagsInContext } from "discourse/lib/hashtag-decorator";
import { wantsNewWindow } from "discourse/lib/intercept-click";
import { PLATFORM_KEY_MODIFIER } from "discourse/lib/keyboard-shortcuts";
import { linkSeenMentions } from "discourse/lib/link-mentions";
import { loadOneboxes } from "discourse/lib/load-oneboxes";
import loadRichEditor from "discourse/lib/load-rich-editor";
import { findRawTemplate } from "discourse/lib/raw-templates";
import { emojiUrlFor, generateCookFunction } from "discourse/lib/text";
@@ -242,45 +237,6 @@ export default class DEditor extends Component {
this.set("preview", cooked);
let unseenMentions, unseenHashtags;
if (this.siteSettings.enable_diffhtml_preview) {
const previewElement = this.element.querySelector(".d-editor-preview");
const cookedElement = previewElement.cloneNode(false);
cookedElement.innerHTML = cooked;
unseenMentions = linkSeenMentions(cookedElement, this.siteSettings);
unseenHashtags = linkSeenHashtagsInContext(
this.site.hashtag_configurations["topic-composer"],
cookedElement
);
loadOneboxes(
cookedElement,
ajax,
this.topicId,
this.categoryId,
this.siteSettings.max_oneboxes_per_post,
/* refresh */ false,
/* offline */ true
);
resolveCachedShortUrls(this.siteSettings, cookedElement);
// trigger all the "api.decorateCookedElement"
this.appEvents.trigger(
"decorate-non-stream-cooked-element",
cookedElement
);
(await import("morphlex")).morph(
previewElement,
cookedElement,
this.morphingOptions
);
}
schedule("afterRender", () => {
if (
this._state !== "inDOM" ||
@@ -294,7 +250,7 @@ export default class DEditor extends Component {
const previewElement = this.element.querySelector(".d-editor-preview");
if (previewElement && this.previewUpdated) {
this.previewUpdated(previewElement, unseenMentions, unseenHashtags);
this.previewUpdated(previewElement);
}
});
}

View File

@@ -2,12 +2,13 @@ import Component from "@glimmer/component";
import { DEBUG } from "@glimmer/env";
import { action } from "@ember/object";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { schedule } from "@ember/runloop";
import { cancel, schedule } from "@ember/runloop";
import { service } from "@ember/service";
import { waitForPromise } from "@ember/test-waiters";
import ItsATrap from "@discourse/itsatrap";
import concatClass from "discourse/helpers/concat-class";
import { bind, debounce } from "discourse/lib/decorators";
import discourseDebounce from "discourse/lib/debounce";
import { bind } from "discourse/lib/decorators";
import { isTesting } from "discourse/lib/environment";
import discourseLater from "discourse/lib/later";
import scrollLock from "discourse/lib/scroll-lock";
@@ -64,8 +65,9 @@ export default class GlimmerSiteHeader extends Component {
this._itsatrap?.destroy();
this._itsatrap = null;
window.removeEventListener("scroll", this._recalculateHeaderOffset);
window.removeEventListener("scroll", this.debouncedRecalculateHeaderOffset);
this._resizeObserver.disconnect();
cancel(this.recalculationTimer);
}
get dropDownHeaderEnabled() {
@@ -84,8 +86,16 @@ export default class GlimmerSiteHeader extends Component {
}
}
@debounce(DEBOUNCE_HEADER_DELAY)
_recalculateHeaderOffset() {
@bind
debouncedRecalculateHeaderOffset() {
this.recalculationTimer = discourseDebounce(
this,
this.recalculateHeaderOffset,
DEBOUNCE_HEADER_DELAY
);
}
recalculateHeaderOffset() {
if (this.isDestroying || this.isDestroyed) {
return;
}
@@ -176,7 +186,7 @@ export default class GlimmerSiteHeader extends Component {
this.headerElement = this._headerWrap.querySelector("header.d-header");
});
window.addEventListener("scroll", this._recalculateHeaderOffset, {
window.addEventListener("scroll", this.debouncedRecalculateHeaderOffset, {
passive: true,
});
@@ -184,7 +194,9 @@ export default class GlimmerSiteHeader extends Component {
const dirs = ["up", "down"];
this._itsatrap.bind(dirs, (e) => this._handleArrowKeysNav(e));
this._resizeObserver = new ResizeObserver(this._recalculateHeaderOffset);
this._resizeObserver = new ResizeObserver(
this.debouncedRecalculateHeaderOffset
);
this._resizeObserver.observe(document.querySelector(".discourse-root"));
}
}
@@ -259,8 +271,10 @@ export default class GlimmerSiteHeader extends Component {
waitForPromise(animationFinished);
cloakElement.animate([{ opacity: 0 }], { fill: "forwards" });
cloakElement.style.display = "block";
if (cloakElement) {
cloakElement.animate([{ opacity: 0 }], { fill: "forwards" });
cloakElement.style.display = "block";
}
animationFinished.then(() => {
if (isTesting()) {

View File

@@ -1,15 +1,16 @@
import Component from "@ember/component";
import EmberObject, { action } from "@ember/object";
import { alias, and, equal, readOnly } from "@ember/object/computed";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { computedI18n } from "discourse/lib/computed";
import discourseComputed from "discourse/lib/decorators";
import { getNativeContact } from "discourse/lib/pwa-utils";
import { emailValid } from "discourse/lib/utilities";
import Group from "discourse/models/group";
import { i18n } from "discourse-i18n";
export default class InvitePanel extends Component {
@service site;
@readOnly("currentUser.staff") isStaff;
@readOnly("currentUser.admin") isAdmin;
@alias("inviteModel.id") topicId;
@@ -307,9 +308,10 @@ export default class InvitePanel extends Component {
}
setGroupOptions() {
Group.findAll().then((groups) => {
this.set("allGroups", groups.filterBy("automatic", false));
});
this.set(
"allGroups",
this.site.groups.filter((g) => !g.automatic)
);
}
@action

View File

@@ -16,7 +16,6 @@ import { canNativeShare, nativeShare } from "discourse/lib/pwa-utils";
import { sanitize } from "discourse/lib/text";
import { applyValueTransformer } from "discourse/lib/transformer";
import { emailValid, hostnameValid } from "discourse/lib/utilities";
import Group from "discourse/models/group";
import Invite from "discourse/models/invite";
import I18n, { i18n } from "discourse-i18n";
import { FORMAT as DATE_INPUT_FORMAT } from "select-kit/components/future-date-input-selector";
@@ -37,21 +36,13 @@ export default class CreateInvite extends Component {
@tracked flashClass = "info";
@tracked topics = this.invite.topics ?? this.model.topics ?? [];
@tracked allGroups;
allGroups = this.site.groups.filter((g) => !g.automatic);
model = this.args.model;
invite = this.model.invite ?? Invite.create();
sendEmail = false;
formApi;
constructor() {
super(...arguments);
Group.findAll().then((groups) => {
this.allGroups = groups.filter((group) => !group.automatic);
});
}
get linkValidityMessageFormat() {
return I18n.messageFormat("user.invited.invite.link_validity_MF", {
user_count: this.defaultRedemptionsAllowed,

View File

@@ -15,7 +15,10 @@ import SmallUserList, {
import UserTip from "discourse/components/user-tip";
import concatClass from "discourse/helpers/concat-class";
import DAG from "discourse/lib/dag";
import { applyMutableValueTransformer } from "discourse/lib/transformer";
import {
applyBehaviorTransformer,
applyMutableValueTransformer,
} from "discourse/lib/transformer";
import { i18n } from "discourse-i18n";
import PostMenuButtonConfig from "./menu/button-config";
import PostMenuButtonWrapper from "./menu/button-wrapper";
@@ -442,26 +445,35 @@ export default class PostMenu extends Component {
@action
async toggleLike() {
if (!this.currentUser) {
this.keyValueStore &&
this.keyValueStore.set({
key: "likedPostId",
value: this.args.post.id,
});
await applyBehaviorTransformer(
"post-menu-toggle-like-action",
async () => {
if (!this.currentUser) {
this.keyValueStore &&
this.keyValueStore.set({
key: "likedPostId",
value: this.args.post.id,
});
this.args.showLogin();
return;
}
this.args.showLogin();
return;
}
if (this.capabilities.userHasBeenActive && this.capabilities.canVibrate) {
navigator.vibrate(VIBRATE_DURATION);
}
if (
this.capabilities.userHasBeenActive &&
this.capabilities.canVibrate
) {
navigator.vibrate(VIBRATE_DURATION);
}
await this.args.toggleLike();
await this.args.toggleLike();
if (!this.collapsed) {
await this.#fetchWhoLiked();
}
if (!this.collapsed) {
await this.#fetchWhoLiked();
}
},
this.staticMethodsArgs
);
}
@action

View File

@@ -1,5 +1,5 @@
<DButton
class="show-advanced-search"
class="show-advanced-search btn-transparent"
title={{i18n "search.open_advanced"}}
@action={{@openAdvancedSearch}}
@icon="sliders"

View File

@@ -2,6 +2,7 @@
id={{this.inputId}}
type="search"
autocomplete="off"
enterkeyhint="search"
value={{this.search.activeGlobalSearchTerm}}
placeholder={{i18n "search.title"}}
aria-label={{i18n "search.title"}}

View File

@@ -7,6 +7,7 @@ import { i18n } from "discourse-i18n";
export default class SearchTextField extends TextField {
autocomplete = "off";
enterkeyhint = "search";
@discourseComputed("searchService.searchContextEnabled")
placeholder(searchContextEnabled) {

View File

@@ -6,10 +6,9 @@ import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import DropdownMenu from "discourse/components/dropdown-menu";
import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n";
import DMenu from "float-kit/components/d-menu";
import MoreSectionLink from "./more-section-link";
import MoreSectionTrigger from "./more-section-trigger";
import SectionLinkButton from "./section-link-button";
export default class SidebarMoreSectionLinks extends Component {
@@ -84,21 +83,14 @@ export default class SidebarMoreSectionLinks extends Component {
<li class="sidebar-section-link-wrapper">
<DMenu
@triggerClass="btn-transparent sidebar-section-link sidebar-more-section-links-details-summary sidebar-row --link-button"
@triggerClass="sidebar-section-link sidebar-more-section-links-details-summary sidebar-row --link-button"
@modalForMobile={{true}}
@autofocus={{true}}
@placement="bottom"
@inline={{true}}
@identifier="sidebar-more-section"
@triggerComponent={{MoreSectionTrigger}}
>
<:trigger>
<span class="sidebar-section-link-prefix icon">
{{icon "ellipsis-vertical"}}
</span>
<span class="sidebar-section-link-content-text">
{{i18n "sidebar.more"}}
</span>
</:trigger>
<:content as |menu|>
<DropdownMenu as |dropdown|>

View File

@@ -0,0 +1,15 @@
import icon from "discourse/helpers/d-icon";
import { i18n } from "discourse-i18n";
const MoreSectionTrigger = <template>
<button ...attributes type="button" class="sidebar-section-link sidebar-row">
<span class="sidebar-section-link-prefix icon">
{{icon "ellipsis-vertical"}}
</span>
<span class="sidebar-section-link-content-text">
{{i18n "sidebar.more"}}
</span>
</button>
</template>;
export default MoreSectionTrigger;

View File

@@ -11,6 +11,7 @@ const DEBOUNCE_MS = 500;
"autocorrect",
"autocapitalize",
"autofocus",
"enterkeyhint",
"maxLength",
"dir",
"aria-label",

View File

@@ -79,6 +79,7 @@
<DMenu
@modalForMobile={{true}}
@identifier="topic-footer-mobile-dropdown"
class="topic-footer-button btn-default"
>
<:trigger>
{{d-icon "ellipsis-vertical"}}

View File

@@ -0,0 +1,216 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { guidFor } from "@ember/object/internals";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import { htmlSafe } from "@ember/template";
import { isEmpty } from "@ember/utils";
import { modifier } from "ember-modifier";
import $ from "jquery";
import DButton from "discourse/components/d-button";
import PickFilesButton from "discourse/components/pick-files-button";
import concatClass from "discourse/helpers/concat-class";
import icon from "discourse/helpers/d-icon";
import { getURLWithCDN } from "discourse/lib/get-url";
import lightbox from "discourse/lib/lightbox";
import { authorizesOneOrMoreExtensions } from "discourse/lib/uploads";
import UppyUpload from "discourse/lib/uppy/uppy-upload";
import { i18n } from "discourse-i18n";
// Args: id, type, imageUrl, placeholderUrl, additionalParams, onUploadDone, onUploadDeleted,
export default class UppyImageUploader extends Component {
@service currentUser;
@service siteSettings;
@tracked imageFilesize;
@tracked imageFilename;
@tracked imageWidth;
@tracked imageHeight;
uppyUpload = new UppyUpload(getOwner(this), {
id: this.args.id,
type: this.args.type,
additionalParams: this.args.additionalParams,
validateUploadedFilesOptions: { imagesOnly: true },
uploadDropTargetOptions: () => ({
target: document.querySelector(
`#${this.args.id} .uploaded-image-preview`
),
}),
uploadDone: (upload) => {
this.imageFilesize = upload.human_filesize;
this.imageFilename = upload.original_filename;
this.imageWidth = upload.width;
this.imageHeight = upload.height;
this.args.onUploadDone(upload);
},
});
applyLightbox = modifier((element) => lightbox(element, this.siteSettings));
willDestroy() {
super.willDestroy(...arguments);
$.magnificPopup?.instance.close();
}
get disabled() {
return (
this.notAllowed ||
this.uppyUpload?.uploading ||
this.uppyUpload?.processing
);
}
get computedId() {
// without a fallback ID this will not be accessible
return this.args.id ? `${this.args.id}__input` : `${guidFor(this)}__input`;
}
get disabledReason() {
if (this.disabled && this.notAllowed) {
return i18n("post.errors.no_uploads_authorized");
}
}
get notAllowed() {
return !authorizesOneOrMoreExtensions(
this.currentUser?.staff,
this.siteSettings
);
}
get showingPlaceholder() {
return !this.args.imageUrl && this.args.placeholderUrl;
}
get placeholderStyle() {
if (isEmpty(this.args.placeholderUrl)) {
return htmlSafe("");
}
return htmlSafe(`background-image: url(${this.args.placeholderUrl})`);
}
get imageCdnUrl() {
if (isEmpty(this.args.imageUrl)) {
return htmlSafe("");
}
return getURLWithCDN(this.args.imageUrl);
}
get backgroundStyle() {
return htmlSafe(`background-image: url(${this.imageCdnUrl})`);
}
get imageBaseName() {
if (!isEmpty(this.args.imageUrl)) {
return this.args.imageUrl.split("/").slice(-1)[0];
}
}
@action
toggleLightbox() {
const lightboxElement = document.querySelector(
`#${this.args.id} a.lightbox`
);
if (lightboxElement) {
$(lightboxElement).magnificPopup("open");
}
}
@action
handleKeyboardActivation(event) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault(); // avoid space scrolling the page
const input = document.getElementById(this.computedId);
if (input && !this.disabled) {
input.click();
}
}
}
<template>
<div {{this.applyLightbox}} id={{@id}} class="image-uploader" ...attributes>
<div
class="uploaded-image-preview input-xxlarge"
style={{this.backgroundStyle}}
>
{{#if this.showingPlaceholder}}
<div
class="placeholder-overlay"
style={{this.placeholderStyle}}
></div>
{{/if}}
<div class="image-upload-controls">
<label
class="btn btn-default pad-left no-text
{{if this.disabled 'disabled'}}"
title={{this.disabledReason}}
for={{this.computedId}}
tabindex="0"
{{on "keydown" this.handleKeyboardActivation}}
>
{{icon "far-image"}}
<PickFilesButton
@registerFileInput={{this.uppyUpload.setup}}
@fileInputDisabled={{this.disabled}}
@acceptedFormatsOverride="image/*"
@fileInputId={{this.computedId}}
/>
</label>
{{#if @imageUrl}}
<DButton
@action={{@onUploadDeleted}}
@icon="trash-can"
class="btn-danger pad-left no-text"
/>
<DButton
@action={{this.toggleLightbox}}
@icon="discourse-expand"
@title="expand"
class="btn-default image-uploader-lightbox-btn no-text"
/>
{{/if}}
<span
class={{concatClass
"btn"
(unless this.uppyUpload.uploading "hidden")
}}
>
{{i18n "upload_selector.uploading"}}
{{this.uppyUpload.uploadProgress}}%
</span>
<span
class={{concatClass
"btn"
(unless this.uppyUpload.processing "hidden")
}}
>{{i18n "upload_selector.processing"}}</span>
</div>
{{#if @imageUrl}}
<a
href={{this.imageCdnUrl}}
title={{this.imageFilename}}
rel="nofollow ugc noopener"
class="lightbox"
>
<div class="meta">
<span class="informations">
{{this.imageWidth}}x{{this.imageHeight}}
{{this.imageFilesize}}
</span>
</div>
</a>
{{/if}}
</div>
</div>
</template>
}

View File

@@ -1,65 +0,0 @@
<div
class="uploaded-image-preview input-xxlarge"
style={{this.backgroundStyle}}
>
{{#if this.showingPlaceholder}}
<div class="placeholder-overlay" style={{this.placeholderStyle}}></div>
{{/if}}
<div class="image-upload-controls">
<label
class="btn btn-default pad-left no-text {{if this.disabled 'disabled'}}"
title={{this.disabledReason}}
for={{this.computedId}}
tabindex="0"
{{on "keydown" this.handleKeyboardActivation}}
>
{{d-icon "far-image"}}
<PickFilesButton
@registerFileInput={{this.uppyUpload.setup}}
@fileInputDisabled={{this.disabled}}
@acceptedFormatsOverride="image/*"
@fileInputId={{this.computedId}}
/>
</label>
{{#if this.imageUrl}}
<DButton
@action={{action "trash"}}
@icon="trash-can"
class="btn-danger pad-left no-text"
/>
<DButton
@icon="discourse-expand"
@title="expand"
@disabled={{this.loadingLightbox}}
@action={{this.toggleLightbox}}
class="btn-default image-uploader-lightbox-btn no-text"
/>
{{/if}}
<span class="btn {{unless this.uppyUpload.uploading 'hidden'}}">{{i18n
"upload_selector.uploading"
}}
{{this.uppyUpload.uploadProgress}}%</span>
<span class="btn {{unless this.uppyUpload.processing 'hidden'}}">{{i18n
"upload_selector.processing"
}}</span>
</div>
{{#if this.imageUrl}}
<a
class="lightbox"
href={{this.imageCDNURL}}
title={{this.imageFilename}}
rel="nofollow ugc noopener"
>
<div class="meta">
<span class="informations">
{{this.imageWidth}}x{{this.imageHeight}}
{{this.imageFilesize}}
</span>
</div>
</a>
{{/if}}
</div>

View File

@@ -1,157 +0,0 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { or } from "@ember/object/computed";
import { guidFor } from "@ember/object/internals";
import { getOwner } from "@ember/owner";
import { next } from "@ember/runloop";
import { htmlSafe } from "@ember/template";
import { isEmpty } from "@ember/utils";
import { classNames } from "@ember-decorators/component";
import { on } from "@ember-decorators/object";
import $ from "jquery";
import discourseComputed from "discourse/lib/decorators";
import { getURLWithCDN } from "discourse/lib/get-url";
import lightbox from "discourse/lib/lightbox";
import { authorizesOneOrMoreExtensions } from "discourse/lib/uploads";
import UppyUpload from "discourse/lib/uppy/uppy-upload";
import { i18n } from "discourse-i18n";
@classNames("image-uploader")
export default class UppyImageUploader extends Component {
@or("notAllowed", "uppyUpload.uploading", "uppyUpload.processing") disabled;
uppyUpload = null;
@on("init")
setupUppyUpload() {
// The uppyUpload configuration depends on arguments. In classic components like
// this one, the arguments are not available during field initialization, so we have to
// defer until init(). When this component is glimmer-ified in future, this can be turned
// into a simple field initializer.
this.uppyUpload = new UppyUpload(getOwner(this), {
id: this.id,
type: this.type,
additionalParams: this.additionalParams,
validateUploadedFilesOptions: { imagesOnly: true },
uploadDropTargetOptions: () => ({
target: document.querySelector(`#${this.id} .uploaded-image-preview`),
}),
uploadDone: (upload) => {
this.setProperties({
imageFilesize: upload.human_filesize,
imageFilename: upload.original_filename,
imageWidth: upload.width,
imageHeight: upload.height,
});
// the value of the property used for imageUrl should be set
// in this callback. this should be done in cases where imageUrl
// is bound to a computed property of the parent component.
if (this.onUploadDone) {
this.onUploadDone(upload);
} else {
this.set("imageUrl", upload.url);
}
},
});
}
@discourseComputed("id")
computedId(id) {
// without a fallback ID this will not be accessible
return id ? `${id}__input` : `${guidFor(this)}__input`;
}
@discourseComputed("disabled", "notAllowed")
disabledReason(disabled, notAllowed) {
if (disabled && notAllowed) {
return i18n("post.errors.no_uploads_authorized");
}
}
@discourseComputed(
"currentUser.staff",
"siteSettings.{authorized_extensions,authorized_extensions_for_staff}"
)
notAllowed() {
return !authorizesOneOrMoreExtensions(
this.currentUser?.staff,
this.siteSettings
);
}
@discourseComputed("imageUrl", "placeholderUrl")
showingPlaceholder(imageUrl, placeholderUrl) {
return !imageUrl && placeholderUrl;
}
@discourseComputed("placeholderUrl")
placeholderStyle(url) {
if (isEmpty(url)) {
return htmlSafe("");
}
return htmlSafe(`background-image: url(${url})`);
}
@discourseComputed("imageUrl")
imageCDNURL(url) {
if (isEmpty(url)) {
return htmlSafe("");
}
return getURLWithCDN(url);
}
@discourseComputed("imageCDNURL")
backgroundStyle(url) {
return htmlSafe(`background-image: url(${url})`);
}
@discourseComputed("imageUrl")
imageBaseName(imageUrl) {
if (isEmpty(imageUrl)) {
return;
}
return imageUrl.split("/").slice(-1)[0];
}
@on("didRender")
_applyLightbox() {
next(() => lightbox(this.element, this.siteSettings));
}
@on("willDestroyElement")
_closeOnRemoval() {
if ($.magnificPopup?.instance) {
$.magnificPopup.instance.close();
}
}
@action
toggleLightbox() {
$(this.element.querySelector("a.lightbox"))?.magnificPopup("open");
}
@action
trash() {
// the value of the property used for imageUrl should be cleared
// in this callback. this should be done in cases where imageUrl
// is bound to a computed property of the parent component.
if (this.onUploadDeleted) {
this.onUploadDeleted();
} else {
this.setProperties({ imageUrl: null });
}
}
@action
handleKeyboardActivation(event) {
if (event.key === "Enter" || event.key === " ") {
event.preventDefault(); // avoid space scrolling the page
const input = document.getElementById(this.computedId);
if (input && !this.disabled) {
input.click();
}
}
}
}

View File

@@ -460,6 +460,9 @@ export default class FullPageSearchController extends Controller {
searching: false,
loading: false,
});
this.appEvents.trigger("search:search_result_view", {
page: args.page,
});
});
break;
}

View File

@@ -824,6 +824,10 @@ export default class TopicController extends Controller.extend(
@action
deletePostWithConfirmation(post, opts) {
if (!post.can_delete) {
return;
}
this.dialog.yesNoConfirm({
message: i18n("post.confirm_delete"),
didConfirm: () => this.send("deletePost", post, opts),

View File

@@ -1,5 +1,4 @@
import Component from "@glimmer/component";
import { concat } from "@ember/helper";
import { action } from "@ember/object";
import { isBlank } from "@ember/utils";
import UppyImageUploader from "discourse/components/uppy-image-uploader";
@@ -23,7 +22,7 @@ export default class FKControlImage extends Component {
<template>
<UppyImageUploader
@id={{concat @field.id "-" @field.name}}
@id="{{@field.id}}-{{@field.name}}"
@imageUrl={{this.imageUrl}}
@onUploadDone={{this.setImage}}
@onUploadDeleted={{this.removeImage}}

View File

@@ -3,6 +3,7 @@ export const BEHAVIOR_TRANSFORMERS = Object.freeze([
"composer-position:editor-touch-move",
"discovery-topic-list-load-more",
"full-page-search-load-more",
"post-menu-toggle-like-action",
]);
export const VALUE_TRANSFORMERS = Object.freeze([

View File

@@ -344,7 +344,10 @@ export default class UppyComposerUpload {
});
const MIN_IMAGES_TO_AUTO_GRID = 3;
if (this.#consecutiveImages?.length >= MIN_IMAGES_TO_AUTO_GRID) {
if (
this.siteSettings.experimental_auto_grid_images &&
this.#consecutiveImages?.length >= MIN_IMAGES_TO_AUTO_GRID
) {
this.#autoGridImages();
}
});

View File

@@ -1,43 +0,0 @@
import EmberObject, { computed } from "@ember/object";
import Mixin from "@ember/object/mixin";
import { isEmpty } from "@ember/utils";
import deprecated from "discourse/lib/deprecated";
import { i18n } from "discourse-i18n";
export default Mixin.create({
init() {
this._super(...arguments);
deprecated(
"NameValidation mixin is deprecated. Use the helper class from discourse/lib/name-validation-helper instead.",
{
id: "discourse.name-validation-mixin",
since: "v3.4.0.beta4-dev",
}
);
},
get nameTitle() {
return i18n(
this.site.full_name_required_for_signup
? "user.name.title"
: "user.name.title_optional"
);
},
// Validate the name.
nameValidation: computed("accountName", "forceValidationReason", function () {
const { accountName, forceValidationReason } = this;
if (this.site.full_name_required_for_signup && isEmpty(accountName)) {
return EmberObject.create({
failed: true,
ok: false,
message: i18n("user.name.required"),
reason: forceValidationReason ? i18n("user.name.required") : null,
element: document.querySelector("#new-account-name"),
});
}
return EmberObject.create({ ok: true });
}),
});

View File

@@ -29,6 +29,7 @@
@enter={{action "search" (hash collapseFilters=true)}}
@hasAutofocus={{this.hasAutofocus}}
@aria-controls="search-result-count"
type="search"
class="full-page-search search no-blur search-query"
/>
<ComboBox

View File

@@ -96,6 +96,11 @@
<div class="controls">
<UppyImageUploader
@imageUrl={{this.model.profile_background_upload_url}}
@onUploadDone={{fn (mut this.model.profile_background_upload_url)}}
@onUploadDeleted={{fn
(mut this.model.profile_background_upload_url)
null
}}
@type="profile_background"
@id="profile-background-uploader"
/>
@@ -116,6 +121,11 @@
<div class="controls">
<UppyImageUploader
@imageUrl={{this.model.card_background_upload_url}}
@onUploadDone={{fn (mut this.model.card_background_upload_url)}}
@onUploadDeleted={{fn
(mut this.model.card_background_upload_url)
null
}}
@type="card_background"
@id="profile-card-background-uploader"
/>

View File

@@ -19,6 +19,8 @@ const MOUSE_OUT_ATTRIBUTE_NAME = "_discourse_mouse_out_widget";
const TOUCH_START_ATTRIBUTE_NAME = "_discourse_touch_start_widget";
const TOUCH_END_ATTRIBUTE_NAME = "_discourse_touch_end_widget";
const TOUCH_MOVE_ATTRIBUTE_NAME = "_discourse_touch_move_widget";
const POINTER_OVER_ATTRIBUTE_NAME = "_discourse_pointer_over_widget";
const POINTER_OUT_ATTRIBUTE_NAME = "_discourse_pointer_out_widget";
class WidgetBaseHook {
constructor(widget) {
@@ -64,6 +66,8 @@ export const WidgetMouseUpHook = buildHook(MOUSE_UP_ATTRIBUTE_NAME);
export const WidgetMouseDownHook = buildHook(MOUSE_DOWN_ATTRIBUTE_NAME);
export const WidgetMouseMoveHook = buildHook(MOUSE_MOVE_ATTRIBUTE_NAME);
export const WidgetMouseOverHook = buildHook(MOUSE_OVER_ATTRIBUTE_NAME);
export const WidgetPointerOverHook = buildHook(POINTER_OVER_ATTRIBUTE_NAME);
export const WidgetPointerOutHook = buildHook(POINTER_OUT_ATTRIBUTE_NAME);
export const WidgetMouseOutHook = buildHook(MOUSE_OUT_ATTRIBUTE_NAME);
export const WidgetTouchEndHook = buildHook(TOUCH_END_ATTRIBUTE_NAME);
@@ -216,6 +220,20 @@ WidgetClickHook.setupDocumentCallback = function () {
})
);
$(document).on(
"pointerover.discourse-widget",
bind(this, (e) => {
nodeCallback(
e.target,
POINTER_OVER_ATTRIBUTE_NAME,
(w) => w.pointerOver(e),
{
rerender: false,
}
);
})
);
$(document).on(
"mouseout.discourse-widget",
bind(this, (e) => {
@@ -225,6 +243,20 @@ WidgetClickHook.setupDocumentCallback = function () {
})
);
$(document).on(
"pointerout.discourse-widget",
bind(this, (e) => {
nodeCallback(
e.target,
POINTER_OUT_ATTRIBUTE_NAME,
(w) => w.pointerOut(e),
{
rerender: false,
}
);
})
);
$(document).on(
"dblclick.discourse-widget",
bind(this, (e) => {

View File

@@ -22,6 +22,8 @@ import {
WidgetMouseOutHook,
WidgetMouseOverHook,
WidgetMouseUpHook,
WidgetPointerOutHook,
WidgetPointerOverHook,
WidgetTouchEndHook,
WidgetTouchMoveHook,
WidgetTouchStartHook,
@@ -484,6 +486,14 @@ export default class Widget {
properties["widget-mouse-over"] = new WidgetMouseOverHook(this);
}
if (this.pointerOver) {
properties["widget-pointer-over"] = new WidgetPointerOverHook(this);
}
if (this.pointerOut) {
properties["widget-pointer-out"] = new WidgetPointerOutHook(this);
}
if (this.mouseOut) {
properties["widget-mouse-out"] = new WidgetMouseOutHook(this);
}

View File

@@ -15,13 +15,13 @@
"test": "ember test"
},
"dependencies": {
"@faker-js/faker": "^9.4.0",
"@faker-js/faker": "^9.5.0",
"@glimmer/syntax": "0.93.1",
"@highlightjs/cdn-assets": "11.11.1",
"@json-editor/json-editor": "2.15.2",
"@messageformat/core": "^3.4.0",
"@messageformat/runtime": "^3.0.1",
"ace-builds": "^1.37.5",
"ace-builds": "^1.38.0",
"decorator-transforms": "^2.3.0",
"discourse-hbr": "workspace:1.0.0",
"discourse-widget-hbs": "workspace:1.0.0",
@@ -48,11 +48,11 @@
"prosemirror-schema-list": "^1.4.1",
"prosemirror-state": "^1.4.3",
"prosemirror-transform": "^1.10.2",
"prosemirror-view": "^1.34.3"
"prosemirror-view": "^1.38.0"
},
"devDependencies": {
"@babel/core": "^7.26.7",
"@babel/standalone": "^7.26.7",
"@babel/core": "^7.26.8",
"@babel/standalone": "^7.26.8",
"@colors/colors": "^1.6.0",
"@discourse/backburner.js": "^2.7.1-0",
"@discourse/itsatrap": "^2.0.10",
@@ -63,7 +63,7 @@
"@ember/string": "^4.0.0",
"@ember/test-helpers": "^5.1.0",
"@ember/test-waiters": "^4.0.0",
"@embroider/compat": "^3.8.0",
"@embroider/compat": "^3.8.1",
"@embroider/core": "^3.5.0",
"@embroider/macros": "^1.16.10",
"@embroider/router": "^2.1.8",
@@ -72,7 +72,7 @@
"@glimmer/component": "^1.1.2",
"@glimmer/tracking": "^1.1.2",
"@popperjs/core": "^2.11.8",
"@swc/core": "^1.10.12",
"@swc/core": "^1.10.15",
"@types/jquery": "^3.5.32",
"@types/qunit": "^2.19.12",
"@types/rsvp": "^4.0.9",
@@ -97,7 +97,7 @@
"ember-auto-import": "^2.10.0",
"ember-buffered-proxy": "^2.1.1",
"ember-cached-decorator-polyfill": "^1.0.2",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-app-version": "^7.0.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-deprecation-workflow": "^3.1.0",
@@ -130,7 +130,7 @@
"select-kit": "workspace:1.0.0",
"sinon": "^19.0.2",
"source-map": "^0.7.4",
"terser": "^5.37.0",
"terser": "^5.38.2",
"testem": "^3.15.2",
"truth-helpers": "workspace:1.0.0",
"util": "^0.12.5",

View File

@@ -10,34 +10,21 @@ let deleteAndBlock;
acceptance("Admin - User Index", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/groups/search.json", () => {
return helper.response([
{
id: 42,
automatic: false,
name: "Macdonald",
user_count: 0,
alias_level: 99,
visible: true,
automatic_membership_email_domains: "",
primary_group: false,
title: null,
grant_trust_level: null,
has_messages: false,
flair_url: null,
flair_bg_color: null,
flair_color: null,
bio_raw: null,
bio_cooked: null,
public_admission: false,
allow_membership_requests: true,
membership_request_template: "Please add me",
full_name: null,
},
]);
});
needs.site({
groups: [
{
id: 42,
automatic: false,
name: "Macdonald",
flair_url: null,
flair_bg_color: null,
flair_color: null,
},
],
});
needs.pretender((server, helper) => {
server.put("/users/sam/preferences/username", () => {
return helper.response({ id: 2, username: "new-sam" });
});

View File

@@ -43,9 +43,7 @@ class FieldHelper {
}
get value() {
this.context
.dom(this.element)
.exists(`Could not find element (name: ${this.name}).`);
this.context.dom(this.element).exists(`field '${this.name}' exists`);
switch (this.element.dataset.controlType) {
case "image": {

View File

@@ -25,7 +25,7 @@ module("Integration | Component | FloatKit | d-menu", function (hooks) {
test("@label", async function (assert) {
await render(hbs`<DMenu @inline={{true}} @label="label" />`);
assert.dom(".fk-d-menu__trigger").containsText("label");
assert.dom(".fk-d-menu__trigger .d-button-label").hasText(/^label$/);
});
test("@icon", async function (assert) {
@@ -428,4 +428,14 @@ module("Integration | Component | FloatKit | d-menu", function (hooks) {
"the pointerdown event isn't propagated to the parent element when the menu is expanded"
);
});
test("@triggerComponent", async function (assert) {
await render(hbs`
<DMenu @inline={{true}} @triggerComponent={{element "span"}}>1</DMenu>
`);
await open();
assert.dom("span.fk-d-menu__trigger").exists();
});
});

View File

@@ -0,0 +1,88 @@
import { hash } from "@ember/helper";
import { render } from "@ember/test-helpers";
import { module, test } from "qunit";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
import selectKit from "discourse/tests/helpers/select-kit-helper";
import GroupChooser from "select-kit/components/group-chooser";
module("Integration | Component | select-kit/group-chooser", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.subject = selectKit();
});
test("limiting the displayed groups", async function (assert) {
const content = [
{
id: 1,
name: "A",
},
{
id: 2,
name: "AB",
},
{
id: 3,
name: "ABC",
},
];
await render(<template>
<GroupChooser
@content={{content}}
@options={{hash displayedGroupsLimit=1}}
/>
</template>);
await this.subject.expand();
assert.strictEqual(
this.subject.rows().length,
1,
"only 1 group is displayed"
);
assert.strictEqual(
this.subject.rowByIndex(0).name(),
"A",
"the first group in the list is displayed"
);
assert
.dom(this.subject.el().querySelector(".filter-for-more"))
.exists("has indicator that there are more groups");
await this.subject.fillInFilter("AB");
assert.strictEqual(
this.subject.rows().length,
1,
"only 1 group is displayed"
);
assert.strictEqual(
this.subject.rowByIndex(0).name(),
"AB",
"the first group that matches the filter in the list is displayed"
);
assert
.dom(this.subject.el().querySelector(".filter-for-more"))
.exists("has indicator that there are more groups matching the filter");
await this.subject.fillInFilter("C");
assert.strictEqual(
this.subject.rows().length,
1,
"only 1 group is displayed"
);
assert.strictEqual(
this.subject.rowByIndex(0).name(),
"ABC",
"the first group that matches the filter in the list is displayed"
);
assert
.dom(this.subject.el().querySelector(".filter-for-more"))
.doesNotExist(
"doesn't have an indicator when there are no more matching elements"
);
});
});

View File

@@ -1,67 +1,70 @@
import { click, render, triggerEvent } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { module, test } from "qunit";
import UppyImageUploader from "discourse/components/uppy-image-uploader";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
module("Integration | Component | uppy-image-uploader", function (hooks) {
setupRenderingTest(hooks);
test("with image", async function (assert) {
await render(hbs`
<UppyImageUploader @type="avatar" @id="uploader" @imageUrl="/images/avatar.png" @placeholderUrl="/not/used.png" />
`);
await render(<template>
<UppyImageUploader
@type="avatar"
@id="uploader"
@imageUrl="/images/avatar.png"
@placeholderUrl="/not/used.png"
/>
</template>);
assert.dom(".d-icon-far-image").exists("displays the upload icon");
assert.dom(".d-icon-trash-can").exists("displays the trash icon");
assert
.dom(".placeholder-overlay")
.doesNotExist("it does not display the placeholder image");
.doesNotExist("does not display the placeholder image");
await click(".image-uploader-lightbox-btn");
assert.strictEqual(
document.querySelectorAll(".mfp-container").length,
1,
"it displays the image lightbox"
);
assert.dom(".mfp-container").exists("displays the image lightbox");
});
test("without image", async function (assert) {
await render(
hbs`<UppyImageUploader @type="site_setting" @id="uploader" />`
);
await render(<template>
<UppyImageUploader @type="site_setting" @id="uploader" />
</template>);
assert.dom(".d-icon-far-image").exists("displays the upload icon");
assert.dom(".d-icon-trash-can").doesNotExist("does not display trash icon");
assert
.dom(".image-uploader-lightbox-btn")
.doesNotExist("it does not display the button to open image lightbox");
.doesNotExist("does not display the button to open image lightbox");
});
test("with placeholder", async function (assert) {
await render(
hbs`<UppyImageUploader @type="composer" @id="uploader" @placeholderUrl="/images/avatar.png" />`
);
await render(<template>
<UppyImageUploader
@type="composer"
@id="uploader"
@placeholderUrl="/images/avatar.png"
/>
</template>);
assert.dom(".d-icon-far-image").exists("displays the upload icon");
assert.dom(".d-icon-trash-can").doesNotExist("does not display trash icon");
assert
.dom(".image-uploader-lightbox-btn")
.doesNotExist("it does not display the button to open image lightbox");
.doesNotExist("does not display the button to open image lightbox");
assert.dom(".placeholder-overlay").exists("displays the placeholder image");
});
test("when dragging image", async function (assert) {
await render(
hbs`
await render(<template>
<UppyImageUploader @type="composer" @id="uploader1" />
<UppyImageUploader @type="composer" @id="uploader2" />
`
);
</template>);
const dropImage = async (target) => {
const dataTransfer = new DataTransfer();

View File

@@ -0,0 +1,42 @@
import { getOwner } from "@ember/owner";
import { click, render } from "@ember/test-helpers";
import { module, test } from "qunit";
import PostMenu from "discourse/components/post/menu";
import { withPluginApi } from "discourse/lib/plugin-api";
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
module("Unit | Component | post-menu", function (hooks) {
setupRenderingTest(hooks);
hooks.beforeEach(function () {
this.siteSettings.glimmer_post_menu_mode = "enabled";
this.siteSettings.post_menu_hidden_items = "";
const store = getOwner(this).lookup("service:store");
const topic = store.createRecord("topic", { id: 123 });
this.post = store.createRecord("post", {
id: 1,
post_number: 1,
topic,
like_count: 3,
actions_summary: [{ id: 2, count: 1, hidden: false, can_act: true }],
});
});
test("post-menu-toggle-like-action behavior transformer", async function (assert) {
withPluginApi("2.0.0", (api) => {
api.registerBehaviorTransformer("post-menu-toggle-like-action", () => {
assert.step("transformer called");
});
});
const post = this.post; // using this inside the template does not correspond to the test `this` context
await render(<template><PostMenu @post={{post}} /></template>);
await click(".post-action-menu__like");
assert.verifySteps(
["transformer called"],
"behavior transformer was called"
);
});
});

View File

@@ -4,6 +4,7 @@ import { on } from "@ember/modifier";
import { action } from "@ember/object";
import { getOwner } from "@ember/owner";
import { service } from "@ember/service";
import curryComponent from "ember-curry-component";
import { modifier } from "ember-modifier";
import { and } from "truth-helpers";
import DButton from "discourse/components/d-button";
@@ -24,8 +25,8 @@ export default class DMenu extends Component {
listeners: true,
});
registerTrigger = modifier((element) => {
this.menuInstance.trigger = element;
registerTrigger = modifier((domElement) => {
this.menuInstance.trigger = domElement;
this.options.onRegisterApi?.(this.menuInstance);
return () => {
@@ -33,8 +34,8 @@ export default class DMenu extends Component {
};
});
registerFloatBody = modifier((element) => {
this.body = element;
registerFloatBody = modifier((domElement) => {
this.body = domElement;
return () => {
this.body = null;
@@ -78,6 +79,35 @@ export default class DMenu extends Component {
};
}
get triggerComponent() {
const instance = this;
const baseArguments = {
get icon() {
return instance.args.icon;
},
get translatedLabel() {
return instance.args.label;
},
get translatedAriaLabel() {
return instance.args.ariaLabel;
},
get translatedTitle() {
return instance.args.title;
},
get disabled() {
return instance.args.disabled;
},
get isLoading() {
return instance.args.isLoading;
},
};
return (
this.args.triggerComponent ||
curryComponent(DButton, baseArguments, getOwner(this))
);
}
get allowedProperties() {
const properties = {};
for (const [key, value] of Object.entries(MENU.options)) {
@@ -87,7 +117,7 @@ export default class DMenu extends Component {
}
<template>
<DButton
<this.triggerComponent
{{this.registerTrigger}}
class={{concatClass
"fk-d-menu__trigger"
@@ -99,12 +129,6 @@ export default class DMenu extends Component {
id={{this.menuInstance.id}}
data-identifier={{this.options.identifier}}
data-trigger
@icon={{@icon}}
@translatedAriaLabel={{@ariaLabel}}
@translatedLabel={{@label}}
@translatedTitle={{@title}}
@disabled={{@disabled}}
@isLoading={{@isLoading}}
aria-expanded={{if this.menuInstance.expanded "true" "false"}}
{{on "keydown" this.forwardTabToContent}}
...attributes
@@ -112,7 +136,7 @@ export default class DMenu extends Component {
{{#if (has-block "trigger")}}
{{yield this.componentArgs to="trigger"}}
{{/if}}
</DButton>
</this.triggerComponent>
{{#if this.menuInstance.expanded}}
{{#if (and this.site.mobileView this.options.modalForMobile)}}

View File

@@ -14,7 +14,7 @@
"start": "ember serve"
},
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"ember-auto-import": "^2.10.0",
"ember-cli-babel": "^8.2.0",
"ember-cli-htmlbars": "^6.3.0",
@@ -29,7 +29,7 @@
"@types/qunit": "^2.19.12",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@@ -159,31 +159,15 @@ function _loadCachedShortUrls(uploadElements, siteSettings, opts) {
break;
case "DIV":
if (siteSettings.enable_diffhtml_preview === true) {
retrieveCachedUrl(upload, siteSettings, "orig-src", opts, (url) => {
const videoHTML = `
<video width="100%" height="100%" preload="metadata" controls style="">
<source src="${url}">
</video>`;
upload.insertAdjacentHTML("beforeend", videoHTML);
upload.classList.add("video-container");
});
} else {
retrieveCachedUrl(
upload,
siteSettings,
"orig-src-id",
opts,
(url) => {
upload.style.backgroundImage = `url('${url}')`;
retrieveCachedUrl(upload, siteSettings, "orig-src-id", opts, (url) => {
upload.style.backgroundImage = `url('${url}')`;
const placeholderIcon = upload.querySelector(
".placeholder-icon.video"
);
placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
}
const placeholderIcon = upload.querySelector(
".placeholder-icon.video"
);
}
placeholderIcon.style.backgroundColor = "rgba(0, 0, 0, 0.3)";
});
break;
}
});

View File

@@ -14,7 +14,7 @@
"start": "ember serve"
},
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"discourse-i18n": "workspace:1.0.0",
"ember-auto-import": "^2.10.0",
"ember-cli-babel": "^8.2.0",
@@ -29,7 +29,7 @@
"@types/qunit": "^2.19.12",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@@ -1,13 +1,52 @@
import { classNames } from "@ember-decorators/component";
import FilterForMore from "select-kit/components/filter-for-more";
import MultiSelectComponent from "select-kit/components/multi-select";
import {
MAIN_COLLECTION,
pluginApiIdentifiers,
selectKitOptions,
} from "select-kit/components/select-kit";
const FILTER_FOR_MORE_GROUPS_COLLECTION = "MORE_GROUPS_COLLECTION";
@classNames("group-chooser")
@selectKitOptions({
allowAny: false,
displayedGroupsLimit: 100,
})
@pluginApiIdentifiers("group-chooser")
export default class GroupChooser extends MultiSelectComponent {}
export default class GroupChooser extends MultiSelectComponent {
init() {
super.init(...arguments);
this.insertAfterCollection(
MAIN_COLLECTION,
FILTER_FOR_MORE_GROUPS_COLLECTION
);
}
modifyComponentForCollection(identifier) {
if (identifier === FILTER_FOR_MORE_GROUPS_COLLECTION) {
return FilterForMore;
}
}
modifyContent(content) {
const limit = this.selectKit.options.displayedGroupsLimit;
if (content.length > limit) {
this.showFilterForMore = true;
content = content.slice(0, limit);
} else {
this.showFilterForMore = false;
}
return content;
}
modifyContentForCollection(identifier) {
if (identifier === FILTER_FOR_MORE_GROUPS_COLLECTION) {
return {
shouldShowMoreTip: this.showFilterForMore,
};
}
}
}

View File

@@ -14,7 +14,7 @@
"start": "ember serve"
},
"dependencies": {
"@babel/core": "^7.26.7",
"@babel/core": "^7.26.8",
"@ember/string": "^4.0.0",
"discourse-i18n": "workspace:1.0.0",
"ember-auto-import": "^2.10.0",
@@ -30,7 +30,7 @@
"@types/qunit": "^2.19.12",
"@types/rsvp": "^4.0.9",
"broccoli-asset-rev": "^3.0.0",
"ember-cli": "~6.1.0",
"ember-cli": "~6.2.0",
"ember-cli-inject-live-reload": "^2.1.0",
"ember-cli-sri": "^2.1.1",
"ember-cli-terser": "^4.0.2",

View File

@@ -7,7 +7,7 @@
"license": "GPL-2.0-only",
"keywords": [],
"dependencies": {
"@babel/standalone": "^7.26.7",
"@babel/standalone": "^7.26.8",
"@zxing/text-encoding": "^0.9.0",
"babel-plugin-ember-template-compilation": "^2.3.0",
"content-tag": "^3.1.1",
@@ -20,7 +20,7 @@
"handlebars": "^4.7.8",
"path-browserify": "^1.0.1",
"polyfill-crypto.getrandomvalues": "^1.0.0",
"terser": "^5.37.0"
"terser": "^5.38.2"
},
"engines": {
"node": ">= 18",

View File

@@ -307,6 +307,13 @@ $mobile-breakpoint: 700px;
max-height: $maxHeight;
overflow: hidden;
position: relative;
color: var(--primary-medium);
@include breakpoint(mobile-extra-large) {
word-wrap: break-word;
max-width: 80vw;
margin-right: 3em;
}
&::after {
content: " ";
@@ -321,12 +328,6 @@ $mobile-breakpoint: 700px;
rgba(var(--secondary-rgb), 0.15)
);
}
@include breakpoint(mobile-extra-large) {
word-wrap: break-word;
max-width: 80vw;
margin-right: 3em;
}
color: var(--primary-medium);
}
}

View File

@@ -386,16 +386,17 @@
max-height: 60vh;
border-bottom-right-radius: var(--d-border-radius);
border-bottom-left-radius: var(--d-border-radius);
border-right: 1px solid var(--primary-low);
border-bottom: 1px solid var(--primary-low);
border-left: 1px solid var(--primary-low);
width: 100%;
@media screen and (max-height: 1000px) {
max-height: 50vh;
}
@media screen and (max-height: 800px) {
max-height: 40vh;
}
border-right: 1px solid var(--primary-low);
border-bottom: 1px solid var(--primary-low);
border-left: 1px solid var(--primary-low);
width: 100%;
&__item:last-child {
border-bottom: none;
@@ -557,10 +558,11 @@
}
.setting-label {
word-wrap: break-word;
@include breakpoint(tablet, min-width) {
width: 25%;
}
word-wrap: break-word;
h3 {
margin-top: 0;

View File

@@ -83,15 +83,16 @@
}
.input-setting-list {
@media (max-width: $mobile-breakpoint) {
width: 100%;
}
padding: 1px;
background-color: var(--secondary);
border: 1px solid var(--primary-low);
border-radius: 3px;
transition: border linear 0.2s, box-shadow linear 0.2s;
@media (max-width: $mobile-breakpoint) {
width: 100%;
}
li.sortable-placeholder {
@include unselectable;
padding: 3px 5px 3px 18px;

View File

@@ -1,4 +1,6 @@
$category-settings-width: unquote("min(500px, 90%)");
@use "sass:string";
$category-settings-width: string.unquote("min(500px, 90%)");
$number-input-width: 75px;
div.edit-category {
@@ -59,7 +61,7 @@ div.edit-category {
.edit-category-tab-general {
.category-chooser {
width: unquote("min(340px, 90%)");
width: min(340px, 90%);
}
}

View File

@@ -65,7 +65,7 @@ html.footer-nav-visible {
@supports (padding: max(0px)) {
.footer-nav.visible {
padding-bottom: unquote("max(5px, env(safe-area-inset-bottom))");
padding-bottom: max(5px, env(safe-area-inset-bottom));
}
}

View File

@@ -4,6 +4,7 @@
.static-login &,
.invite-page &,
.account-created-page &,
.admin-invite-page &,
.activate-account-page & {
display: none !important;
}

View File

@@ -2,6 +2,8 @@
// any variables defined here can be added in theme color schemes
// all variables should have the !default flag
@use "sass:string";
// primary
$primary-very-low: dark-light-diff($primary, $secondary, 97%, -82%) !default;
$primary-low: dark-light-diff($primary, $secondary, 90%, -78%) !default;
@@ -141,9 +143,15 @@ $tertiary-med-or-tertiary: dark-light-choose(
$tertiary
) !default;
$secondary-or-primary: dark-light-choose($secondary, $primary) !default;
$tertiary-or-white: dark-light-choose($tertiary, unquote("#fff")) !default;
$facebook-or-white: dark-light-choose($facebook, unquote("#fff")) !default;
$twitter-or-white: dark-light-choose($twitter, unquote("#fff")) !default;
$tertiary-or-white: dark-light-choose(
$tertiary,
string.unquote("#fff")
) !default;
$facebook-or-white: dark-light-choose(
$facebook,
string.unquote("#fff")
) !default;
$twitter-or-white: dark-light-choose($twitter, string.unquote("#fff")) !default;
// code highlighting
// stack overflow light & dark color pallets

View File

@@ -23,7 +23,7 @@ $SQRT2: 1.4142135623730951;
// fact(0) // 1
// fact(8) // 40320
@function fact($x) {
@if $x < 0 or $x != floor($x) {
@if $x < 0 or $x != math.floor($x) {
@warn "Argument for `fact()` must be a positive integer.";
@return null;
}
@@ -72,7 +72,7 @@ $SQRT2: 1.4142135623730951;
}
$b: $b * $b;
$exp: floor($exp * 0.5);
$exp: math.floor($exp * 0.5);
}
@return $x;
}
@@ -87,7 +87,7 @@ $SQRT2: 1.4142135623730951;
@return math.div(0, 0);
}
$k: nth(frexp(math.div($x, $SQRT2)), 2);
$k: list.nth(frexp(math.div($x, $SQRT2)), 2);
$x: math.div($x, ldexp(1, $k));
$x: math.div($x - 1, $x + 1);
$x2: $x * $x;
@@ -104,7 +104,7 @@ $SQRT2: 1.4142135623730951;
}
@function ipow($base, $exp) {
@if $exp != floor($exp) {
@if $exp != math.floor($exp) {
@return error("Exponent for `ipow()` must be an integer.");
}
@@ -119,7 +119,7 @@ $SQRT2: 1.4142135623730951;
$r: $r * $base;
}
$exp: floor($exp * 0.5);
$exp: math.floor($exp * 0.5);
$base: $base * $base;
}
@return if($s != 0, math.div(1, $r), $r);
@@ -147,7 +147,7 @@ $SQRT2: 1.4142135623730951;
// pow(4, -2) // 0.0625
// pow(4, 0.2) // 1.31951
@function pow($base, $exp) {
@if $exp == floor($exp) {
@if $exp == math.floor($exp) {
@return ipow($base, $exp);
} @else {
@return exp(log($base) * $exp);

View File

@@ -5,7 +5,9 @@
// Media queries
// --------------------------------------------------
@use "sass:color";
@use "sass:math";
@use "sass:string";
$breakpoints: (
mobile-small: 320px,
@@ -19,6 +21,7 @@ $breakpoints: (
);
@mixin breakpoint($bp, $rule: max-width, $type: screen, $sidebar: false) {
/* stylelint-disable-next-line scss/no-global-function-names */
$bp-value: map-get($breakpoints, $bp);
@if $rule == min-width {
@@ -34,6 +37,7 @@ $breakpoints: (
// note that your breakpoint will need to be at the root level
@if $sidebar {
// when the sidebar is shown, we want to increase the breakpoints by the width of the sidebar
/* stylelint-disable-next-line scss/no-global-function-names */
@media #{$type} and (#{$rule}: calc(#{map-get($breakpoints, $bp)} + #{$d-sidebar-width})) {
.has-sidebar-page {
@content;
@@ -170,10 +174,10 @@ $hpad: 0.65em;
$encoded: "";
$slice: 2000;
$index: 0;
$loops: ceil(math.div(str-length($svg), $slice));
$loops: math.ceil(math.div(string.length($svg), $slice));
@for $i from 1 through $loops {
$chunk: str-slice($svg, $index, $index + $slice - 1);
$chunk: string.slice($svg, $index, $index + $slice - 1);
$chunk: str-replace($chunk, '"', "'");
$chunk: str-replace($chunk, "<", "%3C");
$chunk: str-replace($chunk, ">", "%3E");
@@ -194,12 +198,12 @@ $hpad: 0.65em;
/// @param {String} $replace ('') - New value
/// @return {String} - Updated string
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
$index: string.index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace +
@return string.slice($string, 1, $index - 1) + $replace +
str-replace(
str-slice($string, $index + str-length($search)),
string.slice($string, $index + string.length($search)),
$search,
$replace
);
@@ -217,7 +221,7 @@ $hpad: 0.65em;
// rgba(var(--primary-low-rgb), 0.5)
@function hexToRGB($hex) {
@return red($hex), green($hex), blue($hex);
@return color.red($hex), color.green($hex), color.blue($hex);
}
@function schemeType() {
@@ -232,8 +236,9 @@ $hpad: 0.65em;
// public_image_path is added by the stylesheet importer
// it returns a CDN or subfolder path (if applicable).
// SCSS will compile (and return the relative path) if public_image_path is missing.
@if variable-exists(public_image_path) {
@if str-index("#{$path}", "/plugins") == 1 {
/* stylelint-disable-next-line scss/no-global-function-names */
@if global-variable-exists(public_image_path) {
@if string.index("#{$path}", "/plugins") == 1 {
$plugin_asset_path: str-replace($public_image_path, "/images", "");
@return url("#{$plugin_asset_path}#{$path}");
} @else {

View File

@@ -6,7 +6,10 @@
// Layout dimensions
// --------------------------------------------------
@use "sass:color";
@use "sass:math";
@use "sass:meta";
@use "math" as discourse-math;
$small-width: 800px !default;
$medium-width: 995px !default;
@@ -22,17 +25,17 @@ $d-sidebar-narrow-width: 14em !default;
// --------------------------------------------------
$google: #fff !default;
$google-hover: darken($google, 5%) !default;
$google-hover: color.adjust($google, $lightness: -5%) !default;
$instagram: #e1306c !default;
$instagram-hover: darken($instagram, 15%) !default;
$instagram-hover: color.adjust($instagram, $lightness: -15%) !default;
$facebook: #0866ff !default;
$facebook-hover: darken($facebook, 15%) !default;
$facebook-hover: color.adjust($facebook, $lightness: -15%) !default;
$cas: #70ba61 !default;
$twitter: #000 !default;
$github: #100e0f !default;
$github-hover: lighten($github, 20%) !default;
$github-hover: color.adjust($github, $lightness: 20%) !default;
$discord: #7289da !default;
$discord-hover: darken($discord, 10%) !default;
$discord-hover: color.adjust($discord, $lightness: -10%) !default;
// Badge color variables
// --------------------------------------------------
@@ -72,8 +75,6 @@ $line-height-small: var(--line-height-small) !default;
$line-height-medium: var(--line-height-medium) !default;
$line-height-large: var(--line-height-large) !default;
@import "common/foundation/math";
// Z-index
// --------------------------------------------------
@@ -108,10 +109,12 @@ $z-layers: (
@function map-has-nested-keys($map, $keys...) {
@each $key in $keys {
/* stylelint-disable-next-line scss/no-global-function-names */
@if not map-has-key($map, $key) {
@return false;
}
/* stylelint-disable-next-line scss/no-global-function-names */
$map: map-get($map, $key);
}
@return true;
@@ -119,6 +122,7 @@ $z-layers: (
@function map-deep-get($map, $keys...) {
@each $key in $keys {
/* stylelint-disable-next-line scss/no-global-function-names */
$map: map-get($map, $key);
}
@return $map;
@@ -126,7 +130,7 @@ $z-layers: (
@function z($layers...) {
@if not map-has-nested-keys($z-layers, $layers...) {
@warn "No layer defined for `#{inspect($layers...)}` in $z-layers map. Check variables.scss, property omitted.";
@warn "No layer defined for `#{meta.inspect($layers...)}` in $z-layers map- Check variables.scss, property omitted.";
}
@return map-deep-get($z-layers, $layers...);
}
@@ -137,7 +141,8 @@ $z-layers: (
// w3c definition of color brightness https://www.w3.org/TR/AERT#color-contrast
@function dc-color-brightness($color) {
@return (
(red($color) * 0.299) + (green($color) * 0.587) + (blue($color) * 0.114)
(color.red($color) * 0.299) + (color.green($color) * 0.587) +
(color.blue($color) * 0.114)
);
}
@@ -145,18 +150,18 @@ $z-layers: (
@function srgb-scale($foreground, $background, $percent) {
$ratio: math.div($percent, 100%);
$iratio: 1 - $ratio;
$f_r2: red($foreground) * red($foreground);
$f_g2: green($foreground) * green($foreground);
$f_b2: blue($foreground) * blue($foreground);
$b_r2: red($background) * red($background);
$b_g2: green($background) * green($background);
$b_b2: blue($background) * blue($background);
$f_r2: color.red($foreground) * color.red($foreground);
$f_g2: color.green($foreground) * color.green($foreground);
$f_b2: color.blue($foreground) * color.blue($foreground);
$b_r2: color.red($background) * color.red($background);
$b_g2: color.green($background) * color.green($background);
$b_b2: color.blue($background) * color.blue($background);
$r_r2: $f_r2 * $ratio + $b_r2 * $iratio;
$r_g2: $f_g2 * $ratio + $b_g2 * $iratio;
$r_b2: $f_b2 * $ratio + $b_b2 * $iratio;
$r_r: sqrt($r_r2);
$r_g: sqrt($r_g2);
$r_b: sqrt($r_b2);
$r_r: discourse-math.sqrt($r_r2);
$r_g: discourse-math.sqrt($r_g2);
$r_b: discourse-math.sqrt($r_b2);
@return rgb($r_r, $r_g, $r_b);
}
@@ -178,9 +183,9 @@ $z-layers: (
@if dc-color-brightness($adjusted-color) <
dc-color-brightness($comparison-color)
{
@return scale-color($adjusted-color, $lightness: $lightness);
@return color.scale($adjusted-color, $lightness: $lightness);
} @else {
@return scale-color($adjusted-color, $lightness: $darkness);
@return color.scale($adjusted-color, $lightness: $darkness);
}
}
@function dark-light-choose($light-theme-result, $dark-theme-result) {

View File

@@ -9,7 +9,7 @@
#reply-control {
.reply-area {
padding: 6px;
padding-bottom: unquote("max(env(safe-area-inset-bottom), 6px)");
padding-bottom: max(env(safe-area-inset-bottom), 6px);
flex-grow: 1;
min-height: 0;
}

View File

@@ -116,11 +116,6 @@ blockquote {
}
// Special elements
#main-outlet-wrapper {
margin-left: unset;
margin-right: unset;
}
#main-outlet {
padding-top: 1.25em;

View File

@@ -246,10 +246,6 @@ nav.post-controls button.reply .d-icon {
}
}
.post-actions {
/* overriding display: here was causing hidden element to take up space */
}
.post-action {
float: right;
margin-right: 10px;
@@ -432,7 +428,7 @@ span.highlighted {
.posts-filtered-notice {
padding-right: 8.5em;
padding-bottom: unquote("max(1em, env(safe-area-inset-bottom))");
padding-bottom: max(1em, env(safe-area-inset-bottom));
flex-wrap: wrap;
justify-content: flex-start;
margin: 1em -9px;

View File

@@ -28,6 +28,13 @@ class InvitesController < ApplicationController
invite = Invite.find_by(invite_key: params[:id])
# automatically redirect to the topic if the user is logged in and can see it
if current_user
if topic = invite.topics.first
return redirect_to(topic.url) if current_user.guardian.can_see?(topic)
end
end
if invite.present? && invite.redeemable?
show_invite(invite)
else

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class CalculateScores < ::Jobs::Scheduled
every 1.week
def execute(args)
ScoreCalculator.new.calculate
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class CleanUpBookmarks < ::Jobs::Scheduled
every 1.week
def execute(args)
Bookmark.cleanup!
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class CleanUpDrafts < ::Jobs::Scheduled
every 1.week
def execute(args)
Draft.cleanup!
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class CleanUpUserAuthTokens < ::Jobs::Scheduled
every 1.week
def execute(args)
UserAuthToken.cleanup!
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class DeleteRejectedEmails < ::Jobs::Scheduled
every 1.week
def execute(args)
Email::Cleaner.delete_rejected!
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class PurgeOldMiniSchedulerStat < ::Jobs::Scheduled
every 1.week
def execute(args)
MiniScheduler::Stat.purge_old
end
end
end

View File

@@ -0,0 +1,11 @@
# frozen_string_literal: true
module Jobs
class PurgeOldNotifications < ::Jobs::Scheduled
every 1.week
def execute(args)
Notification.purge_old!
end
end
end

View File

@@ -1,19 +0,0 @@
# frozen_string_literal: true
module Jobs
# This job will run on a regular basis to update statistics and denormalized data.
# If it does not run, the site will not function properly.
class Weekly < ::Jobs::Scheduled
every 1.week
def execute(args)
ScoreCalculator.new.calculate
MiniScheduler::Stat.purge_old
Draft.cleanup!
UserAuthToken.cleanup!
Email::Cleaner.delete_rejected!
Notification.purge_old!
Bookmark.cleanup!
end
end
end

View File

@@ -67,7 +67,8 @@ class About
def moderators
@moderators ||=
apply_excluded_groups(
User.where(moderator: true, admin: false).human_users.order(last_seen_at: :desc),
User.where(moderator: true).human_users.order(last_seen_at: :desc),
ignore_groups: [Group::AUTO_GROUPS[:admins]],
)
end
@@ -75,7 +76,10 @@ class About
@admins ||=
DiscoursePluginRegistry.apply_modifier(
:about_admins,
apply_excluded_groups(User.where(admin: true).human_users.order(last_seen_at: :desc)),
apply_excluded_groups(
User.where(admin: true).human_users.order(last_seen_at: :desc),
ignore_groups: [Group::AUTO_GROUPS[:moderators]],
),
)
end
@@ -139,8 +143,8 @@ class About
private
def apply_excluded_groups(query)
group_ids = SiteSetting.about_page_hidden_groups_map
def apply_excluded_groups(query, ignore_groups: [])
group_ids = SiteSetting.about_page_hidden_groups_map - ignore_groups
return query if group_ids.blank?
query.joins(

View File

@@ -97,7 +97,15 @@ class SiteSerializer < ApplicationSerializer
object
.groups
.order(:name)
.select(:id, :name, :flair_icon, :flair_upload_id, :flair_bg_color, :flair_color)
.select(
:id,
:name,
:flair_icon,
:flair_upload_id,
:flair_bg_color,
:flair_color,
:automatic,
)
.map do |g|
{
id: g.id,
@@ -105,6 +113,7 @@ class SiteSerializer < ApplicationSerializer
flair_url: g.flair_url,
flair_bg_color: g.flair_bg_color,
flair_color: g.flair_color,
automatic: g.automatic,
}
end
.as_json

View File

@@ -3,6 +3,11 @@
class UserExportSerializer < ApplicationSerializer
attributes :id, :filename, :uri, :filesize, :extension, :retain_hours, :human_filesize
def serializable_hash(adapter_options = nil, options = {})
return {} unless object.upload
super()
end
def filename
object.upload.original_filename
end

View File

@@ -1,8 +1,50 @@
# frozen_string_literal: true
require "openssl"
require "middleware/omniauth_bypass_middleware"
Rails.application.config.middleware.use Middleware::OmniauthBypassMiddleware
OmniAuth.config.logger = Rails.logger
OmniAuth.config.silence_get_warning = true
OmniAuth.config.request_validation_phase = nil # We handle CSRF checks in before_request_phase
OmniAuth.config.before_request_phase do |env|
request = ActionDispatch::Request.new(env)
# Check for CSRF token in POST requests
CSRFTokenVerifier.new.call(env) if request.request_method.downcase.to_sym != :get
# If the user is trying to reconnect to an existing account, store in session
request.session[:auth_reconnect] = !!request.params["reconnect"]
# If the client provided an origin, store in session to redirect back
request.session[:destination_url] = request.params["origin"]
end
OmniAuth.config.on_failure do |env|
exception = env["omniauth.error"]
# OmniAuth 2 doesn't give us any way to know for sure whether a failure was due to an
# explicit fail! call, or a rescued exception. But, this check is a pretty good guess:
is_rescued_error = exception&.message&.to_sym == env["omniauth.error.type"]
next OmniAuth::FailureEndpoint.call(env) if !is_rescued_error # let the default behavior handle it
case exception
when OAuth::Unauthorized
# OAuth1 (i.e. Twitter) makes a web request during the setup phase
# If it fails, Omniauth does not handle the error. Handle it here
env["omniauth.error.type"] = "request_error"
when JWT::InvalidIatError
# Happens for openid-connect (including google) providers, when the server clock is wrong
env["omniauth.error.type"] = "invalid_iat"
when CSRFTokenVerifier::InvalidCSRFToken
# Happens when CSRF token is missing from request
env["omniauth.error.type"] = "csrf_detected"
else
# default omniauth behavior is to redirect to /auth/failure with error.message in the URL
# We don't want to leak that kind of unhandled exception info, so re-raise it
raise exception
end
OmniAuth::FailureEndpoint.call(env)
end

View File

@@ -655,7 +655,6 @@ ar:
dropdown:
title: "افتح قائمة أحدث المسودات"
untitled: "مسودة دون عنوان"
view_all: "عرض الكل"
other_drafts:
zero: "+%{count} مسودة أخرى"
one: "+ مسودة واحدة (%{count}) أخرى"
@@ -5660,6 +5659,10 @@ ar:
no_results:
title: "لا توجد نتائج"
description: 'لم نتمكن من العثور على أي شيء يطابق "%{filter}".<br><br>هل تريد <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">البحث في إعدادات الموقع</a> أو <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">قائمة المستخدمين ذوي دور المسؤول؟</a>'
footer:
interface_color_selector:
light: "فاتح"
dark: "داكن"
welcome_topic_banner:
title: "إنشاء موضوعك الترحيبي"
description: "إن موضوعك الترحيبي هو أول ما يقرأه الأعضاء الجُدد. انظر إليه على أنه \"عرض ترويجي\" أو \"بيان مهمة\". دَع الجميع يعرفون الجمهور المستهدف بهذا المجتمع، وما يتوقعون العثور عليه هنا، وما تريد منهم أن يفعلوه أولًا."
@@ -6437,8 +6440,6 @@ ar:
community_title: "لقب المجتمع"
community_title_help: "وصف قصير، يظهر في علامة تبويب المتصفح، للصفحات الرئيسية مثل الفئات وقوائم الموضوعات."
banner_image: "صورة البانر"
banner_image_help: |
سيتم استخدام هذا في صفحة "نبذة". الحجم الموصى به: 1100×300 بكسل. الأنواع المقبولة: JPG وPNG وSVG حتى 10 ميغابايت.
contact_information: "معلومات التواصل"
community_owner: "مالك المجتمع"
community_owner_placeholder: "Johnny Smith"
@@ -7732,8 +7733,6 @@ ar:
other: "يتعذَّر حذف جميع المنشورات لأن المستخدم لديه أكثر من %{count} منشور. (delete_all_posts_max)"
delete_confirm_title: "هل تريد بالتأكيد حذف هذا المستخدم؟ لا يمكن التراجع عن هذا الإجراء!"
delete_confirm: "يُفضَّل عامةً إخفاء هوية المستخدمين بدلًا من حذفهم؛ لتجنُّب إزالة المحتوى من المناقشات الحالية."
delete_and_block: "حذف هذا البريد الإلكتروني وعنوان IP و<b>حظرهما</b>"
delete_dont_block: "الحذف فقط"
deleting_user: "جارٍ حذف المستخدم…"
deleted: "تم حذف المستخدم."
delete_failed: "حدث خطأ في أثناء حذف المستخدم. تأكَّد من حذف جميع المنشورات قبل حذف المستخدم."

View File

@@ -1483,6 +1483,10 @@ be:
review:
content: "Патрабуе перагляду"
filter: "Filter..."
footer:
interface_color_selector:
light: "святло"
dark: "цёмна"
form_templates:
upload_field:
upload: "Запампаваць"
@@ -2083,7 +2087,6 @@ be:
confirmation:
cancel: "адмяніць"
delete_forbidden_because_staff: "Адмінаў і мадэратараў выдаляць нельга."
delete_dont_block: "толькі выдаленне"
deleted: "Карыстальніка быў выдалены."
delete_failed: "Пры выдаленні карыстальніка адбылася памылка. Пераканайцеся, што ўсе паведамленні карыстальніка выдалены перад тым, як выдаляць самога карыстальніка."
send_activation_email: "Адправіць ліст для актывацыі"

View File

@@ -4158,8 +4158,6 @@ bg:
cant_delete_all_too_many_posts:
one: "Не може да изтриете всички публикации защото този потребител има %{count} публикация. (delete_all_posts_max)"
other: "Не може да изтриете всички публикации, защото този потребител има повече от %{count} публикации.(delete_all_posts_max) "
delete_and_block: "Изтрийте и <b>блокирайте</b> този имейл и IP адрес "
delete_dont_block: "Изтрий само "
deleted: "Потребителя беше изтрит. "
delete_failed: "Възникна грешка при изтриването на този потребител. Първо се уверете, че всички негови публикации са изтрити и опитайте отново."
send_activation_email: "Изпрати активационен имейл "

View File

@@ -4145,8 +4145,6 @@ bs_BA:
one: "Korisnici se ne mogu izbrisati ako imaju postove. Izbrišite sve postove prije nego pokušate izbrisati korisnika. (Postovi stariji od %{count} dana stari ne mogu se izbrisati.)"
few: "Korisnici se ne mogu izbrisati ako imaju postove. Izbrišite sve postove prije nego pokušate izbrisati korisnika. (Poruke starije od %{count} dana ne mogu se izbrisati.)"
other: "Korisnici ne mogu biti obrisani ako imaju objava. Obrišite sve njihove objave prije nego pokušate obrisati korisnika. (Objave starije od %{count} dana ne mogu biti obrisane.)"
delete_and_block: "Delete and <b>block</b> this email and IP address"
delete_dont_block: "Delete only"
deleted: "The user was deleted."
delete_failed: "There was an error deleting that user. Make sure all posts are deleted before trying to delete the user."
send_activation_email: "Send Activation Email"

View File

@@ -328,8 +328,6 @@ ca:
abandon:
yes_value: "Descarta"
no_value: "Reprèn l'edició"
dropdown:
view_all: "mostra-ho tot"
topic_count_all:
one: "Vegeu %{count} tema nou"
other: "Vegeu %{count} temes nous"
@@ -2954,6 +2952,10 @@ ca:
invite:
content: "Convida"
filter: "Filtre..."
footer:
interface_color_selector:
light: "Clar"
dark: "Fosc"
until: "Fins a:"
form_templates:
upload_field:
@@ -4005,8 +4007,6 @@ ca:
cant_delete_all_too_many_posts:
one: "No es poden suprimir totes les publicacions perquè l'usuari té més d'%{count} publicació. (delete_all_posts_max)"
other: "No es poden suprimir totes les publicacions perquè l'usuari té més de %{count} publicacions. (delete_all_posts_max)"
delete_and_block: "Suprimeix i <b>bloca</i> aquest correu electrònic i aquesta adreça IP"
delete_dont_block: "Només suprimeix"
deleted: "S'ha suprimit l'usuari."
delete_failed: "Hi ha hagut un error en suprimir aquest usuari. Assegureu-vos que totes les seves publicacions són suprimides abans d'intentar suprimir-lo."
send_activation_email: "Envia el correu d'activació"

View File

@@ -561,7 +561,7 @@ cs:
dropdown:
title: "Otevřít nabídku nejnovějších konceptů"
untitled: "Koncept bez názvu"
view_all: "zobrazit vše"
view_all: "zobrazit všechny koncepty"
other_drafts:
one: "+%{count} další koncept"
few: "+%{count} další koncepty"
@@ -640,6 +640,17 @@ cs:
date_filter: "Publikováno mezi"
in_reply_to: "v odpovědi na"
filtered_flagged_by: "Nahlásil"
unknown:
title:
one: "Máte nevyřízené revize ze zakázaného pluginu:"
few: "Máte nevyřízené revize ze zakázaných pluginů:"
many: "Máte nevyřízené revize ze zakázaných pluginů:"
other: "Máte nevyřízené revize ze zakázaných pluginů:"
instruction: "Nelze je správně zobrazit, dokud neaktivujete příslušný plugin. Povolte prosím plugin a obnovte stránku. Případně je můžete ignorovat. <a href='%{url}' target='_blank'>Další informace...</a>"
ignore_all: "Ignorovat vše"
enable_plugins: "Povolit pluginy"
delete_confirm: "Opravdu chcete smazat všechny revize vytvořené zakázanými pluginy?"
ignore_success: "Všechny revize vytvořené zakázanými pluginy byly smazány."
explain:
why: "vysvětlete, proč tato položka skončila ve frontě"
title: "Přezkoumatelné bodování"
@@ -2621,6 +2632,10 @@ cs:
required_at_signup: "Povinné"
optional_at_signup: "Volitelné"
hidden_at_signup: "Volitelné, skryté při registraci"
interface_color_selector:
disabled: "Nezobrazovat"
sidebar_footer: "Zobrazit v zápatí postranního panelu"
header: "Zobrazit v záhlaví"
shortcut_modifier_key:
shift: "Shift"
ctrl: "Ctrl"
@@ -3811,7 +3826,7 @@ cs:
few: "Prosím, vyberte téma, do kterého chcete tyto <b>%{count}</b> příspěvky přesunout."
many: "Prosím, vyberte téma, do kterého chcete těchto <b>%{count}</b> příspěvků přesunout."
other: "Prosím, vyberte téma, do kterého chcete těchto <b>%{count}</b> příspěvků přesunout."
chronological_order: "zachovat chronologické pořadí po sloučení"
chronological_order: "po sloučení zachovat chronologické pořadí"
move_to_new_message:
title: "Přesunout do nové zprávy"
action: "přesunout do nové zprávy"
@@ -4663,6 +4678,7 @@ cs:
content_load_error: '<a href="%url%">Obsah</a> se nepodařilo načíst.'
image_load_error: '<a href="%url%">Obrázek</a> se nepodařilo načíst.'
cannot_render_video: Toto video nelze zobrazit, protože váš prohlížeč nepodporuje daný kodek.
invalid_video_url: Toto video nelze přehrát, protože adresa URL je neplatná nebo nedostupná.
keyboard_shortcuts_help:
shortcut_key_delimiter_comma: ", "
shortcut_key_delimiter_plus: "+"
@@ -5197,6 +5213,11 @@ cs:
no_results:
title: "Žádné výsledky"
description: 'Nenašli jsme nic odpovídajícího ''%{filter}''.<br><br>Chtěli jste <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">prohledávat nastavení webu</a> nebo <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">v seznamu administrace uživatelů?</a>'
footer:
interface_color_selector:
light: "Světlý režim"
dark: "Tmavý režim"
auto: "Automaticky"
welcome_topic_banner:
title: "Vytvořte si uvítací téma"
description: "Vaše uvítací téma je to první, co si noví členové přečtou. Považujte ho za svůj \"elevator pitch\" nebo \"poslání\". Dejte všem vědět, pro koho je tato komunita určena, co zde mohou očekávat a co byste chtěli, aby udělali jako první."
@@ -5392,7 +5413,7 @@ cs:
discourse_last_updated: "Discourse aktualizován:"
version: "Verze Discourse"
up_to_date: "Máte aktuální!"
critical_available: "Je k dispozici důležitá aktualizace."
critical_available: "K dispozici je důležitá aktualizace."
updates_available: "Jsou k dispozici aktualizace."
please_update: "Prosím, aktualizujte!"
no_check_performed: "Kontrola na aktualizace nebyla provedena. Ujistěte se, že běží služby sidekiq."
@@ -5952,8 +5973,6 @@ cs:
community_title: "Titulek komunity"
community_title_help: "Krátký popis, zobrazený na kartě prohlížeče, použitý pro klíčové stránky, jako jsou kategorie a seznamy témat."
banner_image: "Obrázek (banner)"
banner_image_help: |
Bude použit na stránce O tomto webu. Doporučená velikost: 1100x300px. Podporované typy: JPG, PNG a SVG do 10 MB.
contact_information: "Kontaktní informace"
community_owner: "Vlastník komunity"
community_owner_placeholder: "Jan Novák"
@@ -7225,8 +7244,8 @@ cs:
other: "Nelze smazat všechny příspěvky, protože uživatel má více než %{count} příspěvků. (delete_all_posts_max)"
delete_confirm_title: "Jste si jisti, že chcete odstranit tohoto uživatele? Tato akce je trvalá!"
delete_confirm: "Obecně je vhodnější uživatele spíše anonymizovat než mazat, aby se předešlo odstranění obsahu existujících diskusí."
delete_and_block: "Odstranit a <b>zablokovat</b> tento e-mail a IP adresu."
delete_dont_block: "Pouze smazat"
delete_and_block: "Smazat uživatele a zablokovat jeho e-mail a IP adresu"
delete_dont_block: "Smazat uživatele"
deleting_user: "Odstranění uživatele…"
deleted: "Uživatel byl smazán."
delete_failed: "Nastala chyba při odstraňování uživatele. Ujistěte se, že jsou všechny příspěvky tohoto uživatele smazané, než budete uživatele mazat."

View File

@@ -345,8 +345,6 @@ da:
abandon:
yes_value: "Kassér"
no_value: "Genoptag redigering"
dropdown:
view_all: "vis alle"
topic_count_all:
one: "Se %{count} nyt emne"
other: "Se %{count} nye emner"
@@ -3786,6 +3784,10 @@ da:
filter: "Filter..."
no_results:
title: "Ingen resultater"
footer:
interface_color_selector:
light: "Lys"
dark: "Mørk"
until: "Indtil:"
form_templates:
upload_field:
@@ -5098,8 +5100,6 @@ da:
cant_delete_all_too_many_posts:
one: "Kan ikke slette alle indlæg fordi denne bruger har flere end %{count} indlæg. (delete_all_posts_max indstillingen)"
other: "Kan ikke slette alle indlæg fordi denne bruger har flere end %{count} indlæg. (delete_all_posts_max indstillingen)"
delete_and_block: "Slet og <b>bloker</b> denne email og IP-adresse"
delete_dont_block: "Slet kun"
deleting_user: "Sletter bruger…"
deleted: "Brugeren blev slettet."
delete_failed: "Der opstod en fejl ved sletning af brugeren. Kontrollér om alle indlæg er slettet før du prøver at slette brugeren."

View File

@@ -463,7 +463,7 @@ de:
dropdown:
title: "Menü mit den neuesten Entwürfen öffnen"
untitled: "Entwurf ohne Titel"
view_all: "alle ansehen"
view_all: "Alle Entwürfe anzeigen"
other_drafts:
one: "+%{count} anderer Entwurf"
other: "+%{count} andere Entwürfe"
@@ -528,6 +528,15 @@ de:
date_filter: "Gepostet zwischen"
in_reply_to: "Antwort auf"
filtered_flagged_by: "Gemeldet von"
unknown:
title:
one: "Du hast ausstehende Überprüfungen von deaktivierten Plugins:"
other: "Du hast ausstehende Überprüfungen von deaktivierten Plugins:"
instruction: "Sie können erst dann richtig angezeigt werden, wenn du das entsprechende Plugin aktivierst. Bitte aktiviere das Plugin und aktualisiere die Seite. Alternativ kannst du sie auch ignorieren. <a href='%{url}' target='_blank'>Mehr erfahren...</a>"
ignore_all: "Alle ignorieren"
enable_plugins: "Plugins aktivieren"
delete_confirm: "Bist du sicher, dass du alle Bewertungen löschen willst, die von deaktivierten Plugins erstellt wurden?"
ignore_success: "Alle Bewertungen, die von deaktivierten Plugins erstellt wurden, wurden gelöscht."
explain:
why: "erkläre, warum dieses Element in der Warteschlange gelandet ist"
title: "Überprüfbares Scoring"
@@ -2365,6 +2374,10 @@ de:
required_at_signup: "Erforderlich"
optional_at_signup: "Optional"
hidden_at_signup: "Optional, bei der Anmeldung ausgeblendet"
interface_color_selector:
disabled: "Nicht anzeigen"
sidebar_footer: "In der Fußzeile der Seitenleiste anzeigen"
header: "In der Kopfzeile anzeigen"
shortcut_modifier_key:
shift: "Umschalt"
ctrl: "Strg"
@@ -4183,6 +4196,7 @@ de:
content_load_error: '<a href="%url%">Der Inhalt</a> konnte nicht geladen werden.'
image_load_error: '<a href="%url%">Das Bild</a> konnte nicht geladen werden.'
cannot_render_video: Dieses Video kann nicht gerendert werden, da dein Browser den Codec nicht unterstützt.
invalid_video_url: Dieses Video kann nicht abgespielt werden, da die URL ungültig oder nicht verfügbar ist.
keyboard_shortcuts_help:
shortcut_key_delimiter_comma: ", "
shortcut_key_delimiter_plus: "+"
@@ -4673,6 +4687,11 @@ de:
no_results:
title: "Keine Ergebnisse"
description: 'Wir konnten nichts finden, das zu „%{filter}“ passt.<br><br>Wolltest du die <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">Website-Einstellungen</a> oder die <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">Administrator-Benutzerliste</a> durchsuchen?'
footer:
interface_color_selector:
light: "Hell"
dark: "Dunkel"
auto: "Automatisch"
welcome_topic_banner:
title: "Erstelle dein Willkommensthema"
description: "Dein Willkommen-Thema ist das erste, was neue Mitglieder lesen. Betrachte es als dein „Fahrstuhl-Vorstellungsgespräch“ oder „Leitbild“. Hier erfährt jeder, für wen diese Community gedacht ist, was einen hier erwartet und was man direkt zu Beginn tun soll."
@@ -5106,6 +5125,7 @@ de:
Wenn du Bereiche verwendest, kannst du einen API-Schlüssel auf einen bestimmten Satz von Endpunkten beschränken.
Du kannst auch definieren, welche Parameter erlaubt sind. Verwende Kommas, um mehrere Werte zu trennen.
title: Bereiche
one_or_more: Es muss mindestens ein Bereich ausgewählt werden.
granular: Granular
read_only: Nur Lesen
global: Global
@@ -5401,7 +5421,7 @@ de:
community_title_help: "Kurze Beschreibung, die in der Browser-Registerkarte angezeigt wird, für wichtige Seiten wie Kategorien und Themenlisten."
banner_image: "Bannerbild"
banner_image_help: |
Dies wird auf deiner Info-Seite verwendet. Empfohlene Größe: 1100 x 300 px. Akzeptierte Typen: JPG, PNG und SVG bis zu 10 MB.
Empfohlen: 1100x300px. Formate: JPG, PNG, SVG (max. 10 MB).
contact_information: "Kontaktinformationen"
community_owner: "Eigentümer der Community"
community_owner_placeholder: "Max Mustermann"
@@ -6631,8 +6651,8 @@ de:
other: "Nicht alle Beiträge können gelöscht werden, da der Benutzer mehr als %{count} Beiträge hat. (Siehe die Einstellung „delete_all_posts_max“.)"
delete_confirm_title: "Bist du sicher, dass du diesen Benutzer löschen möchtest? Dies kann nicht rückgängig gemacht werden!"
delete_confirm: "Im Allgemeinen ist es besser, Benutzer zu anonymisieren, als sie zu löschen, um zu vermeiden, dass Inhalte aus bestehenden Diskussionen entfernt werden."
delete_and_block: "Löschen und diese E-Mail-Adresse und IP-Adresse <b>blockieren</b>"
delete_dont_block: "Nur löschen"
delete_and_block: "Benutzer löschen und seine E-Mail- und IP-Adresse blockieren"
delete_dont_block: "Benutzer löschen"
deleting_user: "Benutzer wird gelöscht …"
deleted: "Der Benutzer wurde gelöscht."
delete_failed: "Beim Löschen des Benutzers ist ein Fehler aufgetreten. Stelle sicher, dass dieser Benutzer keine Beiträge mehr hat."
@@ -6819,9 +6839,6 @@ de:
more_site_setting_results:
one: "Es gibt mehr als %{count} Ergebnis. Bitte verfeinere deine Suche oder wähle eine Kategorie."
other: "Es gibt mehr als %{count} Ergebnisse. Bitte verfeinere deine Suche oder wähle eine Kategorie."
more_site_setting_results_no_category_sidebar:
one: "Es gibt mehr als %{count} Ergebnis. Bitte grenze deine Suche weiter ein."
other: "Es gibt mehr als %{count} Ergebnisse. Bitte grenze deine Suche weiter ein."
clear_filter: "Filter zurücksetzen"
add_url: "URL hinzufügen"
add_host: "Host hinzufügen"

View File

@@ -428,8 +428,6 @@ el:
abandon:
yes_value: "Απόρριψη"
no_value: "Συνέχιση επεξεργασίας"
dropdown:
view_all: "προβολή όλων"
topic_count_all:
one: "Δείτε %{count} νέο θέμα"
other: "Δείτε %{count} νέα θέματα"
@@ -3907,6 +3905,10 @@ el:
filter: "Φίλτρο..."
no_results:
title: "Δεν υπάρχουν αποτελέσματα"
footer:
interface_color_selector:
light: "Ανοιχτό"
dark: "Σκούρο"
welcome_topic_banner:
title: "Δημιουργήστε το θέμα καλωσορίσματος"
button_title: "Έναρξη Επεξεργασίας"
@@ -5084,8 +5086,6 @@ el:
cant_delete_all_too_many_posts:
one: "Δεν γίνεται να σβήσεις όλες τις αναρτήσεις επειδή ο χρήστης έχει περισσότερες από %{count} αναρτήσεις. (Η ρύθμιση «delete_all_posts_max»)"
other: "Δεν γίνεται να σβήσεις όλες τις αναρτήσεις επειδή ο χρήστης έχει περισσότερες από %{count} αναρτήσεις. (Η ρύθμιση «delete_all_posts_max»)"
delete_and_block: "Σβήσε και <b>απόκλεισε</b> αυτή την διεύθυνση email και τη διεύθυνση IP "
delete_dont_block: "Μόνο διαγραφή"
deleted: "Ο χρήστης διαγράφτηκε."
delete_failed: "Παρουσιάστηκε ένα σφάλμα κατά τη διαγραφή αυτού του χρήστη. Βεβαιώσου πρώτα πως έχουν σβηστεί όλες οι αναρτήσεις του."
send_activation_email: "Αποστολή Email Ενεργοποίησης"

View File

@@ -463,7 +463,6 @@ es:
dropdown:
title: "Abre el menú de últimos borradores"
untitled: "Borrador sin título"
view_all: "ver todo"
other_drafts:
one: "+%{count} otro borrador"
other: "+%{count} otros borradores"
@@ -4673,6 +4672,10 @@ es:
no_results:
title: "No hay resultados"
description: 'No hemos encontrado nada que coincida con «%{filter}».<br><br>¿Quieres <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">buscar en los ajustes del sitio</a> o en la <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">lista de usuarios de administración?</a>'
footer:
interface_color_selector:
light: "Claro"
dark: "Oscuro"
welcome_topic_banner:
title: "Crea tu tema de bienvenida"
description: "Tu tema de bienvenida es lo primero que leerán los nuevos miembros. Piensa en él como tu «discurso breve» o una «declaración de misión». Haz que todos sepan para quién es esta comunidad, qué pueden esperar encontrar aquí y qué te gustaría que hicieran primero."
@@ -5393,8 +5396,6 @@ es:
community_title: "Título de la comunidad"
community_title_help: "Descripción breve, que se muestra en la pestaña del navegador, para páginas clave como categorías y listas de temas."
banner_image: "Imagen del banner"
banner_image_help: |
Se utilizará en tu página Acerca de. Tamaño recomendado: 1100x300px. Tipos aceptados: JPG, PNG y SVG hasta 10 MB.
contact_information: "Información de contacto"
community_owner: "Propietario de la comunidad"
community_owner_placeholder: "Pepe Luis"
@@ -6624,8 +6625,6 @@ es:
other: "No se pueden eliminar todas las publicaciones porque el usuario tiene más de %{count}. (delete_all_posts_max)"
delete_confirm_title: "¿Seguro que quieres eliminar este usuario? ¡Esta acción es permanente!"
delete_confirm: "Normalmente, es mejor anonimizar usuarios en vez de eliminarlos. Así, evitas eliminar contenido de temas existentes."
delete_and_block: "Eliminar y <b>bloquear</b> este correo electrónico y esta dirección IP"
delete_dont_block: "Solo eliminar"
deleting_user: "Eliminando usuario…"
deleted: "El usuario se eliminó"
delete_failed: "Se produjo un error al eliminar este usuario. Asegúrate de que todas sus publicaciones fueron eliminadas antes de intentar de eliminar este usuario."

View File

@@ -2662,6 +2662,10 @@ et:
forum:
label: Foorum
filter: "Filter..."
footer:
interface_color_selector:
light: "Hele"
dark: "Tume"
form_templates:
upload_field:
upload: "Laadi üles"
@@ -3486,8 +3490,6 @@ et:
cant_delete_all_too_many_posts:
one: "Ei saa kustutada kõiki postitusi, sest kasutajal on rohkem, kui %{count} postitus. (delete_all_posts_max)"
other: "Ei saa kustutada kõiki postitusi, sest kasutajal on rohkem, kui %{count} postitust. (delete_all_posts_max)"
delete_and_block: "Kustuta ja <b>blokeeri</b> see meiliaadress ja IP-aadress"
delete_dont_block: "Kustuta vaid"
deleted: "See kasutaja kustutati."
delete_failed: "Viga selle kasutaja kustutamisel. Veendu, et kõik postitused on kustutatud enne kasutaja kustutamist."
send_activation_email: "Saada aktiveerimismeil"

File diff suppressed because it is too large Load Diff

View File

@@ -463,7 +463,6 @@ fi:
dropdown:
title: "Avaa tuoreimpien luonnosten valikko"
untitled: "Nimetön luonnos"
view_all: "katso kaikki"
other_drafts:
one: "+%{count} muu luonnos"
other: "+%{count} muuta luonnosta"
@@ -4673,6 +4672,10 @@ fi:
no_results:
title: "Ei tuloksia"
description: 'Mitään ehtoa %{filter} vastaavaa ei löytynyt.<br><br>Halusitko <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">hakea sivuston asetuksista</a> tai <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">ylläpitäjän käyttäjäluettelosta?</a>'
footer:
interface_color_selector:
light: "Vaalea"
dark: "Tumma"
welcome_topic_banner:
title: "Luo tervetuloketjusi"
description: "Tervetuloketjusi on ensimmäinen asia, jonka uudet jäsenet lukevat. Ajattele sitä \"hissipuheenasi\" tai \"tavoitelausumanasi\". Kerro kaikille, kenelle tämä yhteisö on tarkoitettu, mitä he voivat odottaa löytävänsä täältä ja mitä haluat heidän tekevän ensin."
@@ -5393,8 +5396,6 @@ fi:
community_title: "Yhteisön otsikko"
community_title_help: "Lyhyt kuvaus, joka näkyy selaimen välilehdellä tärkeimmillä sivuilla, kuten alueissa ja ketjuluetteloissa."
banner_image: "Bannerikuva"
banner_image_help: |
Tätä käytetään Tietoa-sivullasi. Suositeltu koko: 1 100 x 300 px. Hyväksytyt tyypit: JPG, PNG ja SVG, enintään 10 Mt.
contact_information: "Yhteystiedot"
community_owner: "Yhteisön omistaja"
community_owner_placeholder: "Matti Meikäläinen"
@@ -6624,8 +6625,6 @@ fi:
other: "Kaikkia viestejä ei voi poistaa, koska käyttäjällä on enemmän kuin %{count} viestiä. (delete_all_posts_max)"
delete_confirm_title: "Oletko varma, että haluat poistaa tämän käyttäjän? Käyttäjä poistetaan pysyvästi!"
delete_confirm: "On yleensä parempi anonymisoida käyttäjät poistamisen sijaan; näin vältät sisällön poistamisen olemassa olevista keskusteluista."
delete_and_block: "Poista ja <b>estä</b> tämä sähköposti ja IP-osoite"
delete_dont_block: "Ainoastaan poista"
deleting_user: "Poistetaan käyttäjää…"
deleted: "Käyttäjä poistettiin."
delete_failed: "Käyttäjän poistanen ei onnistunut. Varmista, että kaikki käyttäjän viestit on poistettu."

View File

@@ -463,7 +463,6 @@ fr:
dropdown:
title: "Ouvrir le menu des derniers brouillons"
untitled: "Brouillon sans titre"
view_all: "tout voir"
other_drafts:
one: "+%{count} autre brouillon"
other: "+%{count} autres brouillons"
@@ -1410,7 +1409,7 @@ fr:
all_tags: "Toutes les étiquettes"
warnings: "Avertissements officiels"
read_more_in_group: "Vous voulez en savoir plus ? Parcourez les autres messages dans %{groupLink}."
read_more: "Vous voulez en savoir plus ? Parcourez les autres messages dans les <a href='%{basePath}/u/%{username}/messages'>messages personnels</a>."
read_more: "Vous voulez en savoir plus ? Parcourez les autres messages dans les <a href='%{basePath}/u/%{username}/messages'>messages privés</a>."
read_more_group_pm_MF: |
{ HAS_UNREAD_AND_NEW, select,
true {
@@ -1449,20 +1448,20 @@ fr:
}
{ NEW, plural,
=0 {}
one { et <a href="{basePath}/u/{username}/messages/new"># nouveau message</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
other { et <a href="{basePath}/u/{username}/messages/new"># nouveaux messages</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
one { et <a href="{basePath}/u/{username}/messages/new"># nouveau message</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
other { et <a href="{basePath}/u/{username}/messages/new"># nouveaux messages</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
}
}
false {
{ UNREAD, plural,
=0 {}
one {Il y a <a href="{basePath}/u/{username}/messages/unread"># message non lu</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
other {Il y a <a href="{basePath}/u/{username}/messages/unread"># messages non lus</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
one {Il y a <a href="{basePath}/u/{username}/messages/unread"># message non lu</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
other {Il y a <a href="{basePath}/u/{username}/messages/unread"># messages non lus</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
}
{ NEW, plural,
=0 {}
one {Il y a <a href="{basePath}/u/{username}/messages/new"># nouveau message</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
other {Il y a <a href="{basePath}/u/{username}/messages/new"># nouveaux messages</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages personnels</a>}
one {Il y a <a href="{basePath}/u/{username}/messages/new"># nouveau message</a> restant, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
other {Il y a <a href="{basePath}/u/{username}/messages/new"># nouveaux messages</a> restants, ou parcourez les autres <a href="{basePath}/u/{username}/messages">messages privés</a>}
}
}
other {}
@@ -1773,7 +1772,7 @@ fr:
always: "toujours"
only_when_away: "seulement en cas d'absence"
never: "jamais"
email_messages_level: "Envoyez-moi un e-mail lorsque je reçois un message personnel"
email_messages_level: "Envoyez-moi un e-mail lorsque je reçois un message privé"
include_tl0_in_digests: "Inclure les contributions des nouveaux utilisateurs dans les résumés par e-mail"
email_in_reply_to: "En plus du message notifié par e-mail, inclure un extrait du message auquel il répond"
other_settings: "Autre"
@@ -2877,7 +2876,7 @@ fr:
sr_menu_tabs: "Onglets du menu utilisateur"
view_all_notifications: "afficher toutes les notifications"
view_all_bookmarks: "voir tous les signets"
view_all_messages: "voir tous les messages personnels"
view_all_messages: "voir tous les messages privés"
tabs:
all_notifications: "Toutes les notifications"
replies: "Réponses"
@@ -3335,7 +3334,7 @@ fr:
help: "Ouvrir une version de ce sujet adaptée à l'impression"
flag_topic:
title: "Signaler"
help: "signaler ce sujet en privé pour attirer l'attention ou envoyer un message direct à son propos"
help: "signaler ce sujet en privé pour attirer l'attention ou envoyer un message privé à son propos"
success_message: "Vous avez signalé ce sujet avec succès."
make_public:
title: "Convertir en sujet public"
@@ -3617,7 +3616,7 @@ fr:
edit_action: "Modifier"
edit_anonymous: "Nous sommes désolés, mais vous devez être connecté(e) pour modifier ce message."
flag_action: "Signaler"
flag: "signaler cette publication en privé pour attirer l'attention ou envoyer un message direct à son propos"
flag: "signaler cette publication en privé pour attirer l'attention ou envoyer un message privé à son propos"
anonymous_flag: "envoyer un e-mail au personnel pour signaler cette publication"
delete_action: "Supprimer la publication"
delete: "supprimer ce message"
@@ -4491,7 +4490,7 @@ fr:
no_replies_title_others: "%{username} n'a encore répondu à aucun sujet"
no_replies_body: "Lorsque vous <a href='%{searchUrl}'>découvrez</a> une conversation intéressante à laquelle vous souhaitez contribuer, appuyez sur le bouton <kbd>Répondre</kbd> directement sous n'importe quel message pour répondre au message. Ou, si vous préférez répondre au sujet général plutôt qu'à un message individuel ou à une personne, recherchez le bouton <kbd>Répondre</kbd> tout en bas du sujet, ou sous la chronologie du sujet."
no_drafts_title: "Vous n'avez enregistré aucun brouillon"
no_drafts_body: "Vous n'êtes pas tout à fait prêt(e) à publier ? Nous enregistrerons automatiquement un nouveau brouillon et le répertorierons ici chaque fois que vous commencerez à rédiger un sujet, une réponse ou un message personnel. Sélectionnez le bouton Annuler pour supprimer ou enregistrez votre brouillon pour continuer plus tard."
no_drafts_body: "Vous n'êtes pas tout à fait prêt(e) à publier ? Nous enregistrerons automatiquement un nouveau brouillon et le répertorierons ici chaque fois que vous commencerez à rédiger un sujet, une réponse ou un message privé. Sélectionnez le bouton Annuler pour supprimer ou enregistrez votre brouillon pour continuer plus tard."
no_likes_title: "Vous n'avez encore aimé aucun sujet"
no_likes_title_others: "%{username} n'a encore aimé aucun sujet"
no_likes_body: "Pour commencer à intervenir et à contribuer, il est judicieux de lire les conversations qui ont déjà eu lieu et de sélectionner le %{heartIcon} sur les messages que vous aimez !"
@@ -4673,6 +4672,10 @@ fr:
no_results:
title: "Aucun résultat"
description: 'Nous n''avons rien trouvé correspondant à « %{filter} ».<br><br>Vouliez-vous <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">rechercher dans les paramètres du site</a> ou dans la <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">liste des utilisateurs administrateurs ?</a>'
footer:
interface_color_selector:
light: "Clair"
dark: "Sombre"
welcome_topic_banner:
title: "Créez votre sujet de bienvenue"
description: "Votre sujet de bienvenue est la première chose que les nouveaux membres liront. Considérez-le comme votre « argumentaire » ou votre « énoncé de mission ». Faites savoir à tout le monde à qui est destinée cette communauté, ce qu'ils peuvent s'attendre à y trouver et ce que vous aimeriez qu'ils fassent en premier."
@@ -5394,8 +5397,6 @@ fr:
community_title: "Titre de la communauté"
community_title_help: "Brève description, affichée dans l'onglet du navigateur, pour les pages clés telles que les catégories et les listes de sujets."
banner_image: "Image de bannière"
banner_image_help: |
Ce fichier sera utilisé sur votre page À propos. Taille recommandée : 1 100 x 300 px. Types acceptés : JPG, PNG et SVG jusqu'à 10 Mo.
contact_information: "Informations de contact"
community_owner: "Propriétaire de la communauté"
community_owner_placeholder: "Johnny Smith"
@@ -6625,8 +6626,6 @@ fr:
other: "Impossible de supprimer tous les messages parce que l'utilisateur a plus de %{count} messages. (delete_all_posts_max)"
delete_confirm_title: "Voulez-vous vraiment supprimer cet utilisateur ? Cette action est définitive !"
delete_confirm: "Il est généralement préférable d'anonymiser les utilisateurs plutôt que de les supprimer, afin d'éviter de supprimer du contenu dans les discussions existantes."
delete_and_block: "Supprimer et <b>bloquer</b> cette adresse e-mail et adresse IP."
delete_dont_block: "Supprimer uniquement"
deleting_user: "Suppression de l'utilisateur…"
deleted: "L'utilisateur a été supprimé."
delete_failed: "Une erreur s'est produite lors de la suppression de cet utilisateur. Assurez-vous que tous les messages sont supprimés avant d'essayer de supprimer l'utilisateur."

View File

@@ -311,8 +311,6 @@ gl:
abandon:
yes_value: "Desbotar"
no_value: "Retomar a edición"
dropdown:
view_all: "ver todos"
topic_count_all:
one: "Ver %{count} tema novo"
other: "Ver %{count} temas novos"
@@ -3369,6 +3367,10 @@ gl:
invite:
content: "Convidar"
filter: "Filtrar..."
footer:
interface_color_selector:
light: "Claro"
dark: "Escuro"
until: "Ata:"
form_templates:
upload_field:
@@ -4558,8 +4560,6 @@ gl:
cant_delete_all_too_many_posts:
one: "Non é posíbel eliminar todas as publicacións porque o usuario ten máis dunha publicación. (delete_all_posts_max)"
other: "Non é posíbel eliminar todas as publicacións porque o usuario ten máis de %{count} publicacións. (delete_all_posts_max)"
delete_and_block: "Eliminar e <b>bloquear</b> este enderezo de correo e de IP"
delete_dont_block: "Só eliminar"
deleted: "Eliminouse o usuario."
delete_failed: "Produciuse un erro eliminando este usuario. Asegúrese de que se eliminan todas as publicacións antes de tentar eliminar o usuario."
send_activation_email: "Enviar mensaxe de correo de activación"

View File

@@ -561,7 +561,7 @@ he:
dropdown:
title: "פתיחת תפריט הטיוטות האחרונות"
untitled: "טיוטה ללא שם"
view_all: "להציג הכול"
view_all: "הצגת כל הטיוטות"
topic_count_all:
one: "הצגת נושא חדש"
two: "הצגת שני נושאים חדשים"
@@ -635,6 +635,17 @@ he:
date_filter: "פורסם בין"
in_reply_to: "בתגובה ל"
filtered_flagged_by: "סומן על ידי"
unknown:
title:
one: "יש לך פריטים שממתינים לבדיקה מתוסף מושבת:"
two: "יש לך פריטים שממתינים לבדיקה מתוספים מושבתים:"
many: "יש לך פריטים שממתינים לבדיקה מתוספים מושבתים:"
other: "יש לך פריטים שממתינים לבדיקה מתוספים מושבתים:"
instruction: "אי אפשר להציג אותם כראוי עד להפעלת התוסף המתאים. נא להפעיל את התוסף ולרענן את העמוד. לחלופין, אפשר להתעלם מהם. <a href='%{url}' target='_blank'>מידע נוסף…</a>"
ignore_all: "התעלמות מהכול"
enable_plugins: "הפעלת תוספים"
delete_confirm: "למחוק את כל הביקורות שנוצרו על ידי תוספים שהושבתו?"
ignore_success: "כל הביקורות שנוצרו על ידי תוספים שהושבתו תימחקנה."
explain:
why: "נא להסביר למה הפריט הזה הגיע לתור"
title: "ניקוד שניתן לסקירה"
@@ -2611,6 +2622,10 @@ he:
required_at_signup: "נדרש"
optional_at_signup: "רשות"
hidden_at_signup: "רשות, יוסתר בהרשמה"
interface_color_selector:
disabled: "לא להציג"
sidebar_footer: "להציג בתחתית סרגל הצד"
header: "הצגה בכותרת"
shortcut_modifier_key:
shift: "Shift"
ctrl: "Ctrl"
@@ -4076,6 +4091,9 @@ he:
delete_topic_confirm_modal_no: "לא, להשאיר את הנושא הזה"
delete_topic_error: "אירעה שגיאה בעת מחיקת הנושא"
delete_topic: "מחיקת נושא"
add_post_notice: "הוספת הודעה רשמית…"
change_post_notice: "עריכת הודעה רשמית…"
delete_post_notice: "מחיקת הודעה רשמית"
remove_timer: "הסרת שעון עצר"
edit_timer: "עריכת מתזמן"
actions:
@@ -4636,6 +4654,7 @@ he:
content_load_error: 'אין אפשרות לטעון את ה<a href="%url%">תוכן הזה</a>.'
image_load_error: 'אין אפשרות לטעון את ה<a href="%url%">תמונה הזו</a>.'
cannot_render_video: לא ניתן לעבד את הסרטון הזה מכיוון שהדפדפן שלך אינו תומך במקודד.
invalid_video_url: אי אפשר לנגן את הסרטון הזה כי הכתובת שגויה או לא זמינה.
keyboard_shortcuts_help:
shortcut_key_delimiter_comma: ", "
shortcut_key_delimiter_plus: "+"
@@ -5170,6 +5189,11 @@ he:
no_results:
title: "אין תוצאות"
description: 'לא מצאנו שום דבר שעונה לחיפוש %{filter}.<br><br>התכוונת במקרה <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">לחפש בהגדרות האתר</a> או ב<a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">רשימת משתמשי ההנהלה?</a>'
footer:
interface_color_selector:
light: "בהיר"
dark: "כהה"
auto: "אוט׳"
welcome_topic_banner:
title: "כאן ניתן ליצור את נושא קבלת הפנים שלך"
description: "נושא קבלת הפנים שלך הוא הדבר הראשון שחברים חדשים יקראו. אפשר לחשוב על זה כמו על „נאום מעלית” או „הצהרת כוונות”. כדאי לתאר למי מיועדת הקהילה הזאת, מה אפשר לצפות למצוא כאן ומה מומלץ לעשות בהתחלה."
@@ -5314,6 +5338,9 @@ he:
legal:
title: "משפטי"
header_description: "הגדרת התצוגה המשפטית, כגון תנאי השירות, מדיניות פרטיות, פרטי יצירת קשר ונושאים נקודתיים לאיחוד האירופי"
localization:
title: "תרגום"
header_description: "הגדרת שפת הממשק של הקהילה שלך ואפשרויות התאמה מקומיות אחרות עבור החברים"
login_and_authentication:
title: "כניסה ואימות"
header_description: "הגדרה איך משתמשים נכנסים ועוברים אימות, סודות ומפתחות, ספקי OAuth2 ועוד"
@@ -5430,6 +5457,22 @@ he:
reports:
trend_title: "%{percent} שינוי. כרגע הערך עומד על %{current}, היה %{prev} בתקופת הבדיקה הקודמת."
percent_change_tooltip: "%{percent} שינוי."
percent_change_tooltip_previous_value:
yesterday:
one: "היה %{count} לפני יומיים."
two: "היה %{count} לפני יומיים."
many: "היה %{count} לפני יומיים."
other: "היה %{count} לפני יומיים."
two_weeks_ago:
one: "היה %{count} לפני שבועיים."
two: "היה %{count} לפני שבועיים."
many: "היה %{count} לפני שבועיים."
other: "היה %{count} לפני שבועיים."
thirty_days_ago:
one: "היה %{count} ב־30 הימים הקודמים."
two: "היה %{count} ב־30 הימים הקודמים."
many: "היה %{count} ב־30 הימים הקודמים."
other: "היה %{count} ב־30 הימים הקודמים."
today: "היום"
yesterday: "אתמול"
last_7_days: "7 הימים האחרונים"
@@ -5606,6 +5649,7 @@ he:
בעת שימוש בתחומים, ניתן להגביל מפתח API לקבוצה מסוימת של נקודות גישה.
ניתן גם להגדיר אילו משתנים יורשו. ניתן להשתמש בפסיקים כדי להפריד מגוון ערכים.
title: תחומים
one_or_more: יש לבחור לפחות תחום אחד.
granular: נקודתי
read_only: לקריאה בלבד
global: גלובלי
@@ -5848,6 +5892,9 @@ he:
group_permissions: "הרשאות קבוצתיות"
users: "משתמשים"
groups: "קבוצות"
localization:
title: "תרגום"
keywords: "מקום|שפה|אזור זמן|unicode|rtl"
user_fields: "שדות משתמש"
watched_words: "מילים במעקב"
legal: "משפטי"
@@ -5903,8 +5950,6 @@ he:
community_title: "כותרת הקהילה"
community_title_help: "תיאור קצר שמופיע בלשונית הדפדפן, לעמודי מפתח כגון רשימות קטגוריות ונושאים."
banner_image: "תמונת כרזה"
banner_image_help: |
ייעשה בזה שימוש בעמוד העל אודות שלך. הגודל המומלץ: 1100×300 פיקסלים. סוגים מורשים: JPG, PNG ו־SVG עד 10 מ״ב
contact_information: "פרטי קשר"
community_owner: "בעלות על הקהילה"
community_owner_placeholder: "יוסי כהן"
@@ -6187,6 +6232,7 @@ he:
customize_desc: "התאמה אישית:"
title: "ערכות עיצוב"
description: "ערכות עיצוב הן ערכות מתרחבות שמשנות מגוון פריטי עיצוב לסגנון הפורום שלך ובדרך כלל כוללים גם יכולות מצד מנשק המשתמש."
components_description: "רכיבים הם פריטי התאמה קטנים יותר שאפשר להוסיף לערכות עיצוב כדי לשנות קטעים מסוימים של סגנון עיצוב הפורום שלך."
create: "יצירה"
create_type: "סוג"
create_name: "שם"
@@ -6290,6 +6336,7 @@ he:
install_git_repo: "ממאגר git"
install_create: "יצירת חדשה"
installing_message: "ערכת העיצוב החדשה שלך מוגדרת…"
installing_message_long_time: "הגדרת ערכת העיצוב החדשה שלך אורכת מעבר למצופה, נא להמתין בסבלנות…"
duplicate_remote_theme: "רכיב ערכת העיצוב „%{name}” כבר מותקן, להתקין עותק נוסף?"
force_install: "לא ניתן להתקין את ערכת העיצוב כיוון שמאגר ה־Git אינו נגיש. להמשיך בהתקנתה?"
create_placeholder: "יצירת ממלא מקום"
@@ -6483,6 +6530,7 @@ he:
instructions: "התאמת התבנית שמשמשת כתבנית להודעות html, לצד עיצוב עם CSS."
email:
title: "הודעות דוא״ל"
description: "אפשר להתאים את התבנית שמשמשת ליצירת הודעות דוא״ל, הודעות תקציר בדוא״ל שתישלחנה ולצפות ביומני דוא״ל."
settings: "הגדרות"
templates: "תבניות"
templates_title: "תבניות דוא״ל"
@@ -6502,6 +6550,7 @@ he:
bounced: "הוחזר"
received: "התקבל"
rejected: "נדחה"
sent_at: "נשלח ב־"
time: "זמן"
user: "משתמש"
email_type: "סוג דוא״ל"
@@ -6569,6 +6618,7 @@ he:
post_approved: "פוסט אושר"
logs:
title: "יומנים וסינון"
description: "יומנים ובחינה מאפשרים לך לעקוב ולנהל את הקהילה שלך כדי לוודא שהיא נשארת בטוחה ומכבדת. אפשר לצפות ביומני כל הפעולות שננקטו על ידי חברי הסגל, לחפש ביומנים ולבחון התנהגות של משתמשים."
nav_title: "יומנים"
action: "פעולה"
created_at: "נוצר"
@@ -7077,10 +7127,18 @@ he:
time_read: "זמן קריאה"
post_edits_count: "עריכות של פוסטים"
exports:
title: היטלי ייצוא של משתמשים
download:
description: הורדת הייצוא האחרון
expires_in:
one: יפוג בעוד שעה
two: יפוג בעוד שעתיים
many: יפוג בעוד %{count} שעות
other: יפוג בעוד %{count} שעות
not_available: אין ייצוא זמין
button: בקשת ארכיון
confirm: ליצור ארכיון של פעילות והעדפות המשתמש הזה?
started: התחלנו לאסוף את הארכיון, הקישור להורדה יתעדכן עם סיום התהליך.
success: הארכיון מוכן להורדה.
export_failed: הייצוא נכשל, עמך הסליחה. נא לעיין ביומנים לקבלת מידע נוסף.
anonymize: "הפיכת משתמשים לאלמוניים"
@@ -7151,8 +7209,8 @@ he:
other: "לא ניתן להסיר את כל הפוסטים בגלל שלמשתמשים יותר מ %{count} פוסטים. (delete_all_posts_max)"
delete_confirm_title: "למחוק את המשתמש הזה? המחיקה היא לצמיתות!"
delete_confirm: "עדיף להפוך משתמשים לאלמוניים במקום למחוק אותם כדי להימנע מהסרת תוכן מדיונים קיימים."
delete_and_block: "מחיקה ו<b>חסימה</b> של כתובות הדוא״ל וה־IP האלו"
delete_dont_block: "מחיקה בלבד"
delete_and_block: "מחיקה של המשתמש ומחיקת כתובת הדוא״ל וה־IP הזה"
delete_dont_block: "מחיקת משתמש"
deleting_user: "משתמש נמחק…"
deleted: "המשתמש נמחק."
delete_failed: "הייתה שגיאה במחיקת המשתמש. יש לוודא שכל הפוסטים נמחקו לפני ניסיון להסיר את המשתמש."
@@ -7665,6 +7723,7 @@ he:
homepage_choices:
custom:
label: "מותאם"
description: "להציג עמוד בית מוכוון %{type} עם נחיתת משתמשים ב%{landingPage}"
style_type:
categories: "קטגוריה"
topics: "נושא"

View File

@@ -474,8 +474,6 @@ hr:
confirm: "Već imate nacrt u tijeku. Što biste željeli učiniti s njim?"
yes_value: "Odbaci"
no_value: "Nastavi uređivati"
dropdown:
view_all: "pregledaj sve"
topic_count_all:
one: "Pregledajte %{count} nepročitanu temu."
few: "Pregledajte %{count} nove teme."
@@ -5747,8 +5745,6 @@ hr:
few: "Ne možete obrisati sve objave jer korisnik ima više od %{count} objava. (briši_sve_objave_max)"
other: "Ne možete obrisati sve objave jer korisnik ima više od %{count} objava. (briši_sve_objave_max)"
delete_confirm: "Općenito je bolje anonimizirati korisnike umjesto brisanja, kako bi se izbjeglo uklanjanje sadržaja iz postojećih rasprava."
delete_and_block: "Obriši i <b>block</b> ovaj email i IP adresu"
delete_dont_block: "Samo obriši"
deleted: "Korisnik je obrisan."
delete_failed: "Dogodila se greška pri brisanju korisnika. Provjerite da li ste obrisali sve njegove objave prije nego ga ponovo pokušate brisati."
send_activation_email: "Pošalji aktivacijski email"

View File

@@ -27,7 +27,7 @@ hu:
millions: "%{number}m"
dates:
time: "HH:mm"
time_short: "ó:pp"
time_short: "h:mm"
time_with_zone: "HH:mm (z)"
time_short_day: "ddd, HH:mm"
timeline_date: "YYYY. MMMM"
@@ -37,11 +37,11 @@ hu:
long_with_year: "YYYY. MMM D., HH:mm"
long_with_year_no_time: "YYYY. MMM D."
full_with_year_no_time: "YYYY. MMMM D."
long_date_with_year: "YYYY.MM.DD LT"
long_date_with_year: "YYYY. MM. DD. LT"
long_date_without_year: "MMM D., HH:mm"
long_date_with_year_without_time: "YYYY.MM.DD"
long_date_with_year_without_time: "YYYY. MM. DD."
long_date_without_year_with_linebreak: "MMM D.<br />HH:mm"
long_date_with_year_with_linebreak: "YYYY.MM.DD <br/>LT"
long_date_with_year_with_linebreak: "YYYY. MM. DD. <br/>LT"
wrap_ago: "ennyi ideje: %{date}"
wrap_on: "ekkor: %{date}"
tiny:
@@ -106,7 +106,7 @@ hu:
almost_x_years:
one: "majdnem %{count} év"
other: "majdnem %{count} év"
date_year: "YYYY.MM.DD"
date_year: "YYYY. MM. DD."
medium_with_ago:
x_minutes:
one: "%{count} perce"
@@ -151,9 +151,9 @@ hu:
last_item: "és"
action_codes:
public_topic: "Téma nyilvánossá téve: %{when}"
open_topic: "Témává alakította %{when}"
open_topic: "Témává alakítva: %{when}"
private_topic: "Téma privát üzenetté alakítva: %{when}"
split_topic: "Felosztotta a témát ekkor: %{when}"
split_topic: "Téma felosztva: %{when}"
invited_user: "Meghívva: %{who} %{when}"
invited_group: "Meghívva: %{who} %{when}"
user_left: "%{who} eltávolította magát ebből az üzenetből ekkor: %{when}"
@@ -190,7 +190,7 @@ hu:
emails_are_disabled: "Egy adminisztrátor letiltotta a kimenő e-maileket. Semmilyen értesítő e-mail nem lesz elküldve."
emails_are_disabled_non_staff: "A kimenő e-mailek le vannak tiltva a nem stábtagok számára."
software_update_prompt:
message: "Frissítettük ezt az oldalt, <span>kérlek, frissíts</span> a zökkenőmentes működésért."
message: "Frissítettük ezt az oldalt, <span>frissítse</span> a zökkenőmentes működésért."
dismiss: "Elvetés"
bootstrap_mode: "Első lépések"
back_button: "Vissza"
@@ -204,11 +204,11 @@ hu:
broken_plugin_alert: "A '%{name}' bővítmény okozta."
broken_transformer_alert: "Hiba történt. Előfordulhat, hogy webhelye nem működik megfelelően."
critical_deprecation:
notice: "<b>[Admin Értesítés]</b> Az egyik témád vagy bővítményed frissítésre szorul a Discourse magjának közelgő változásaival való kompatibilitás érdekében."
id: "(azonosító<em>%{id}</em>)"
notice: "<b>[Adminisztrátori megjegyzés]</b> Az egyik témája vagy bővítménye kompatibilitási frissítésre szorul a Discourse magjának közelgő változásai miatt."
id: "(azonosító:<em>%{id}</em>)"
linked_id: "(azonosító:<a href='%{url}' target='_blank'><em>%{id}</em></a>)"
theme_source: "Azonosított téma: <a target='_blank' href='%{path}'>'%{name}'</a>."
plugin_source: "Azonosított bővítmény: '%{name}'"
theme_source: "Azonosított téma: <a target='_blank' href='%{path}'>%{name}</a>."
plugin_source: "Azonosított bővítmény: %{name}"
s3:
regions:
ap_northeast_1: "Csendes-óceáni térség (Tokió)"
@@ -307,7 +307,7 @@ hu:
moderators: "Moderátorok"
stat:
all_time: "Mindenkori"
last_day: "24 óráig"
last_day: "24 óra"
last_7_days: "7 nap"
last_30_days: "30 nap"
like_count: "Kedvelés"
@@ -327,13 +327,13 @@ hu:
} az Európai Unióból valósi.
contact: "Kapcsolatfelvétel"
contact_info: "A webhellyel kapcsolatos sürgős vagy kritikus probléma esetén lépjen velünk kapcsolatba a következő elérhetőségen: %{contact_info}."
site_activity: "Oldal tevékenység"
view_more: "Mutass többet"
view_less: "Mutass kevesebbet"
site_activity: "Oldaltevékenység"
view_more: "Több megtekintése"
view_less: "Kevesebb megtekintése"
activities:
topics:
one: "%{formatted_number} téma"
other: "%{formatted_number} témák"
other: "%{formatted_number} téma"
posts:
one: "%{formatted_number} bejegyzés"
other: "%{formatted_number} bejegyzés"
@@ -349,7 +349,7 @@ hu:
visitors_MF: |
{ total_count, plural,
one {{total_formatted_number} látogató}
other {{total_formatted_number} ~ látogató}
other {{total_formatted_number} látogató}
}, körülbelül { eu_count, plural,
one {{eu_formatted_number}}
other {{eu_formatted_number}}
@@ -357,17 +357,17 @@ hu:
periods:
last_7_days: "az elmúlt 7 napban"
today: "ma"
all_time: "mindenkori"
all_time: "valaha"
member_count:
one: "%{formatted_number} Tag"
other: "%{formatted_number} Tag"
one: "%{formatted_number} tag"
other: "%{formatted_number} tag"
admin_count:
one: "%{formatted_number} Adminisztrátor"
other: "%{formatted_number} Adminisztrátor"
one: "%{formatted_number} adminisztrátor"
other: "%{formatted_number} adminisztrátor"
moderator_count:
one: "%{formatted_number} Moderátor"
other: "%{formatted_number} Moderátor"
report_inappropriate_content: "Ha bármilyen nem megfelelő tartalommal találkozik, ne habozzon kapcsolatba lépni moderátorainkkal és adminjainkkal. Ne felejtsen el bejelentkezni, mielőtt felvenné velünka a kapcsolatot."
one: "%{formatted_number} moderátor"
other: "%{formatted_number} moderátor"
report_inappropriate_content: "Ha bármilyen nem megfelelő tartalommal találkozik, ne habozzon kapcsolatba lépni moderátorainkkal és adminjainkkal. Ne felejtsen el bejelentkezni, mielőtt felvenné velük a kapcsolatot."
site_age:
less_than_one_month: "Létrehozva < 1 hónapja"
month:
@@ -381,14 +381,14 @@ hu:
edit_bookmark: "Könyvjelző szerkesztése"
clear_bookmarks: "Könyvjelzők törlése"
help:
bookmark: "Kattintson a téma könyvjelzővé tételéhez"
bookmark: "Kattintson a téma könyvjelzőzéséhez"
edit_bookmark: "Kattintson a témában lévő hozzászólás könyvjelzőjének szerkesztéséhez."
edit_bookmark_for_topic: "Kattintson a témához tartozó könyvjelző szerkesztéséhez"
unbookmark: "Kattintson a téma valamennyi könyvjelzőjének törléséhez"
unbookmark_with_reminder: "Kattintson ide a téma összes könyvjelzőjének és emlékeztetőjének eltávolításához."
bookmarks:
also_set_reminder: "Beállít emlékeztetőt?"
bookmarked_success: "könyvjelzőztem!"
bookmarked_success: "Könyvjelzőzve!"
deleted_bookmark_success: "Könyvjelző törölve!"
reminder_set_success: "Emlékeztető beállítva!"
created: "Könyvjelzőzte ezt a bejegyzést. %{name}"
@@ -413,15 +413,15 @@ hu:
when_reminder_sent: "Könyvjelző törlése"
on_owner_reply: "Könyvjelző törlése, amint válaszolok"
clear_reminder: "Könyvjelző megtartása és az emlékeztető törlése"
after_reminder_label: "Miután emlékeztettünk, hogy..."
after_reminder_checkbox: "Állítsd be ezt alapértelmezettként az összes jövőbeli könyvjelző emlékeztetőhöz."
after_reminder_label: "Az emlékeztetés után…"
after_reminder_checkbox: "Ennek a beállítása alapértelmezettként az összes jövőbeli könyvjelző-emlékeztetőhöz."
search_placeholder: "Könyvjelzők keresése név, téma címe vagy tartalom alapján"
search: "Keresés"
bookmark: "Könyvjelző"
bulk:
delete_completed: "Könyvjelzők sikerresen törölve."
reminders_cleared: "Könyvjelző emlékeztetők sikeresen törölve."
toggle: "kapcsolja be a könyvjelzők tömeges kiválasztását"
delete_completed: "Könyvjelzők sikeresen törölve."
reminders_cleared: "Könyvjelző-emlékeztetők sikeresen törölve."
toggle: "könyvjelzők csoportos kiválasztása be/ki"
select_all: "Összes kiválasztása"
clear_all: "Összes törlése"
selected_count:
@@ -442,7 +442,7 @@ hu:
name: "Könyvjelző törlése"
description:
one: "Biztos, hogy törli ezt a könyvjelzőt?"
other: "Biztos, hogy törli ezt a <b>%{count}</b> könyvjelzőt?"
other: "Biztos, hogy törli ezt a(z) <b>%{count}</b> könyvjelzőt?"
copy_codeblock:
copied: "másolva!"
copy: "kód másolása a vágólapra"
@@ -462,14 +462,13 @@ hu:
no_value: "Szerkesztés folytatása"
dropdown:
title: "Legújabb piszkozatok menü megnyitása"
untitled: "Névtelen vázlat"
view_all: "mindent megtekint"
untitled: "Névtelen piszkozat"
other_drafts:
one: "+%{count} egyéb piszkozat"
other: "+%{count} egyéb piszkozat"
topic_count_all:
one: "Nézzen meg %{count} új témát"
other: "Nézzen meg %{count} új témát"
one: "%{count} új téma megtekintése"
other: "%{count} új téma megtekintése"
topic_count_categories:
one: "Nézzen meg %{count} új vagy frissített témát"
other: "Nézzen meg %{count} új vagy frissített témát"
@@ -487,12 +486,12 @@ hu:
other: "Nézzen meg %{count} új témát"
preview: "előnézet"
cancel: "mégse"
deleting: "Törlés"
deleting: "Törlés"
save: "Módosítások mentése"
saving: "Mentés..."
saving: "Mentés"
saved: "Mentve!"
upload: "Feltöltés"
uploading: "Feltöltés..."
uploading: "Feltöltés"
processing: "Feldolgozás…"
uploading_filename: "Feltöltés: %{filename}…"
processing_filename: "Feldolgozás: %{filename}…"
@@ -504,7 +503,7 @@ hu:
continue: "Folytatás"
switch_to_anon: "Anonim módba lépés"
switch_from_anon: "Kilépés az anonim módból"
select_placeholder: "Kiválaszt..."
select_placeholder: "Kiválasztás…"
none_placeholder: "Egyik sem"
banner:
close: "Kiemelés eltávolítása"
@@ -522,8 +521,8 @@ hu:
search: "Üzenet keresése"
placeholder: "írja ide az üzenet címét, URL-jét vagy azonosítóját"
review:
show_more: "Mutass többet"
show_less: "Mutass kevesebbet"
show_more: "Több megjelenítése"
show_less: "Kevesebb megjelenítése"
order_by: "Rendezés:"
date_filter: "Ezek közt közzétéve"
in_reply_to: "válasz erre:"
@@ -549,12 +548,12 @@ hu:
name: "típusbónusz"
title: "Bizonyos felülvizsgálandó típusokat a stáb bónuszban részesíthet, hogy magasabb prioritást kapjanak."
revise_and_reject_post:
title: "Felülvizsgál"
title: "Felülvizsgálat"
reason: "Ok"
send_pm: "PÜ küldése"
feedback: "Visszajelzés"
custom_reason: "Adj egyértelmű leírást az okról"
other_reason: "Egyéb..."
custom_reason: "Adjon egyértelmű leírást az okáról"
other_reason: "Egyéb"
optional: "nem kötelező"
stale_help: "Ezt a felülvizsgálandó elemet <b>%{username}</b> oldotta meg."
claim_help:
@@ -639,7 +638,7 @@ hu:
category: "Kategória"
score_type:
title: "Ok"
all: "(minden ok)"
all: "(összes ok)"
orders:
score: "Pontszám"
score_asc: "Pontszám (fordított)"
@@ -672,7 +671,7 @@ hu:
approved_user:
title: "Felhasználó jóváhagyva"
approved_post:
title: "Hozzászólás jóváhagyva"
title: "Bejegyzés jóváhagyva"
rejected:
title: "Elutasítva"
rejected_flag:
@@ -680,13 +679,13 @@ hu:
rejected_user:
title: "Felhasználó elutasítva"
rejected_post:
title: "A bejegyzés elutasítva"
title: "Bejegyzés elutasítva"
ignored:
title: "Megjelölés figyelmen kívül hagyva"
deleted:
title: "Téma vagy bejegyzés törölve"
reviewed:
title: "Minden áttekintve"
title: "Összes áttekintett"
all:
title: "Összes"
context_question:
@@ -766,7 +765,7 @@ hu:
never: "Soha"
last_custom: "Legutóbbi egyéni dátum/idő"
custom: "Egyéni dátum és idő"
more_options: "További lehetőségek..."
more_options: "További lehetőségek"
select_timeframe: "Válasszon egy időkeretet"
user_action:
user_posted_topic: "<a href='%{userUrl}'>%{user}</a> közzétett <a href='%{topicUrl}'>egy témát</a>"
@@ -796,7 +795,7 @@ hu:
post_count: "Válasz"
post_count_long: "Közzétett válasz"
no_results:
body: "A közösségi tagok aktivitását bemutató lista itt jelenik meg. A lista egyelőre üres, mert a közösség még teljesen új!"
body: "A közösségi tagok tevékenységei itt fognak megjelenni. A lista egyelőre üres, mert a közösség még teljesen új!"
extra_body: "Az adminisztrátorok és moderátorok a <a href='%{basePath}/admin/users/'>Felhasználók</a> oldalon láthatják és kezelhetik a felhasználókat."
no_results_with_search: "Nincs találat."
days_visited: "Látogatás"
@@ -874,7 +873,7 @@ hu:
imap_alpha_warning: "Figyelmeztetés: ez egy alfa fázisú funkció. Hivatalosan csak a Gmail támogatott. Saját felelősségre használja."
imap_settings_valid: "Az IMAP beállítások érvényesek."
smtp_disable_confirm: "Ha letiltja az SMTP-t, akkor az összes SMTP- és IMAP-beállítás visszaáll, és a kapcsolódó funkciók le lesznek tiltva. Biztos, hogy folytatni akarja?"
imap_disable_confirm: "Ha letiltja az IMAP-ot, akkor az összes IMAP-beállítás visszaáll, és a kapcsolódó funkciók le lesznek tiltva. Biztos, hogy folytatni akarja?"
imap_disable_confirm: "Ha letiltja az IMAP-ot, akkor az összes IMAP-beállítás alaphelyzetbe áll, és a kapcsolódó funkciók le lesznek tiltva. Biztos, hogy folytatja?"
imap_mailbox_not_selected: "Választani kell egy postaládát ehhez az IMAP-beállításhoz, különben egyetlen postafiók sem lesz szinkronizálva."
prefill:
title: "Beállítások előre kitöltése ehhez:"
@@ -945,7 +944,7 @@ hu:
empty:
posts: "A csoport tagjai még nem írtak bejegyzést"
members: "Nincsenek tagok ebben a csoportban"
requests: "Nincsenek tagsági kérelmek ennél a csoportnál"
requests: "Nincsenek tagsági kérések ennél a csoportnál"
mentions: "Nincsenek említések erről a csoportról"
messages: "Nincsenek üzenetek ehhez a csoporthoz"
topics: "A csoport tagjai még nem hoztak létre témát"
@@ -1022,7 +1021,7 @@ hu:
no_filter_matches: "Egyetlen tag sem felel meg a keresésnek."
topics: "Témák"
posts: "Bejegyzések"
aria_post_number: "%{title} - %{postNumber} bejegyzés"
aria_post_number: "%{title} %{postNumber}. bejegyzés"
mentions: "Említések"
messages: "Üzenetek"
notification_level: "Csoportos üzenetek alapértelmezett értesítési szintje"
@@ -1090,9 +1089,9 @@ hu:
no_subcategories: "nincsenek alkategóriák"
remove_filter: "szűrő eltávolítása"
plus_more_count:
one: "+még %{count}"
other: "+még %{count}"
view_all: "mindent megtekint"
one: "+%{count} további"
other: "+%{count} további"
view_all: "összes megtekintése"
category: "Kategória"
category_list: "Kategória lista megjelenítése"
reorder:
@@ -1149,7 +1148,7 @@ hu:
user_fields:
none: "(válasszon egy lehetőséget)"
required: 'Adja meg a(z) „%{name}” értékét'
required_checkbox: 'A(z) "%{name}" mező kitöltése kötelező'
required_checkbox: 'A(z) %{name} mező kitöltése kötelező'
same_as_password: "A jelszavát nem szabad megismételnie más mezőkben"
optional: (nem kötelező)
user:
@@ -1161,8 +1160,8 @@ hu:
edit: "Beállítások szerkesztése"
download_archive:
title: "Adatok exportálása"
description: "A fiókhoz tartozó tevékenységek és beállítások archívumának letöltése"
button_text: "Archívum letöltése"
description: "A fiókhoz tartozó tevékenységek és beállítások archívumának letöltése."
button_text: "Archívum kérése"
confirm: "Szeretné letölteni a fiók tevékenységének és beállításainak archívumát?"
success: "Megkezdtük az archívum összegyűjtését, üzenetet fog kapni, ha a folyamat befejeződik."
rate_limit_error: "A fiókarchívumokat naponta egyszer lehet letölteni, kérjük, próbálja meg holnap újra."
@@ -1185,7 +1184,7 @@ hu:
ignore_no_users: "Nincsenek figyelmen kívül hagyott felhasználók."
ignore_option: "Figyelmen kívül hagyva"
ignore_option_title: "Nem fog semmilyen értesítést kapni ezzel a felhasználóval kapcsolatban, és az összes tartalma el lesz rejtve."
add_ignored_user: "Új..."
add_ignored_user: "Hozzáadás…"
mute_option: "Némított"
mute_option_title: "Nem fog semmilyen értesítést, személyes üzenetet vagy közvetlen üzenetet kapni ettől a felhasználótól."
normal_option: "Normál"
@@ -1221,7 +1220,7 @@ hu:
warning: "Biztos, hogy törli a kiemelt témát?"
use_current_timezone: "Jelenlegi időzóna használata"
profile_hidden: "A felhasználó nyilvános profilja rejtett."
login_to_view_profile: "A felhasználói profilok megtekintéséhez be kell jelentkezned"
login_to_view_profile: "A felhasználói profilok megtekintéséhez be kell jelentkeznie"
inactive_user: "Ez a felhasználó már nem aktív."
expand_profile: "Kibontás"
sr_expand_profile: "Profiladatok kibontása"
@@ -1248,10 +1247,10 @@ hu:
dismiss_notifications: "Összes elvetése"
dismiss_notifications_tooltip: "Minden olvasatlan értesítés olvasottnak jelölése"
dismiss_bookmarks_tooltip: "Az összes olvasatlan könyvjelző-emlékeztető megjelölése olvasottként"
dismiss_messages_tooltip: "Jelölje olvasottnak az összes olvasatlan személyes üzenetről szóló értesítést"
no_likes_title: "Még nem kaptál kedvelést"
dismiss_messages_tooltip: "Az összes olvasatlan személyes üzenetről szóló értesítés olvasottnak jelölése"
no_likes_title: "Még nem kapott kedvelést"
no_likes_body: >
Itt értesítést kap, ha valaki kedveli valamelyik bejegyzését, így láthatja, hogy mások mit tartanak értékesnek. Mások is látni fogják, ha Ön kedveli az ő posztjaikat! <br><br> A kedvelésekről szóló értesítésekről soha nem küldünk Önnek e-mailt, de a <a href='%{preferencesUrl}'> értesítési beállítások között</a> beállíthatja, hogy miként kapjon értesítést a kedvelésekről az oldalon.
Itt értesítést kap, ha valaki kedveli valamelyik bejegyzését, így láthatja, hogy mások mit tartanak értékesnek. Mások is látni fogják, ha Ön kedveli a bejegyzésüket! <br><br> A kedvelésekről szóló értesítésekről soha nem küldünk e-mailt, de az <a href='%{preferencesUrl}'> értesítési beállítások között</a> beállíthatja, hogy miként kapjon értesítést a kedvelésekről az oldalon.
no_messages_title: "Nincsenek üzenetei"
no_messages_body: >
Közvetlen személyes beszélgetésre van szüksége valakivel a szokásos beszélgetési folyamaton kívül? Üzenetet küldhet a profilképe kiválasztásával, és az %{icon} üzenet gombra kattintással.<br><br> Ha segítségre van szüksége, akkor <a href='%{aboutUrl}'>üzenjen egy stábtagnak</a>.
@@ -1264,7 +1263,7 @@ hu:
Ebben a panelben fog értesítést kapni az Ön számára közvetlenül releváns tevékenységekről, köztük a témákra és bejegyzésekre adott válaszokról, arról ha valaki <b>@megemlíti</b> vagy idézi Önt, illetve az Ön által figyelt témákra adott válaszokról. Az értesítéseket e-mailben is meg fogja kapni, ha már egy ideje nem lépett be. <br><br>Keresse a %{icon} ikont, hogy eldöntse, mely témákról, kategóriákról és címkékről akar értesítést kapni. A továbbiakért tekintse meg az <a href='%{preferencesUrl}'>értesítési beállításait</a>.
no_other_notifications_title: "Még nincsenek értesítései"
no_other_notifications_body: >
Ezen a panelen értesítést fog kapni az Önt érintő egyéb tevékenységekről - például ha valaki hivatkozik az Ön egyik bejegyzésére vagy szerkeszti azt.
Ezen a panelen értesítést fog kapni az Önt érintő egyéb tevékenységekről például, ha valaki hivatkozik az Ön egyik bejegyzésére vagy szerkeszti azt.
no_notifications_page_title: "Még nincsenek értesítései"
no_notifications_page_body: >
Értesítést fog kapni az Ön számára közvetlenül releváns tevékenységekről, köztük a témákra és bejegyzésekre adott válaszokról, arról ha valaki <b>@megemlíti</b> vagy idézi Önt, illetve az Ön által figyelt témákra adott válaszokról. Az értesítéseket e-mailben is meg fogja kapni, ha már egy ideje nem lépett be. <br><br>Keresse a %{icon} ikont, hogy eldöntse, mely témákról, kategóriákról és címkékről akar értesítést kapni. A továbbiakért tekintse meg az <a href='%{preferencesUrl}'>értesítési beállításait</a>.
@@ -1273,7 +1272,7 @@ hu:
description: "Új felhasználói belépési tippek és jelvények kihagyása"
reset_seen_user_tips: "Felhasználói tippek ismételt megjelenítése"
theme_default_on_all_devices: "Legyen ez az alapértelmezett téma az összes eszközén"
color_scheme_default_on_all_devices: "Alapértelmezett színpaletta beállítása minden eszközömön"
color_scheme_default_on_all_devices: "Alapértelmezett színpaletta beállítása az összes eszközén"
color_scheme: "Színpaletta"
color_schemes:
default_description: "Téma alapértelmezése"
@@ -1284,7 +1283,7 @@ hu:
dark: "Sötét mód"
default_dark_scheme: "(webhely alapértelmezése)"
dark_mode: "Sötét mód"
dark_mode_enable: "Automatikus sötét mód színpaletta engedélyezése"
dark_mode_enable: "Automatikus, sötét módú színpaletta engedélyezése"
text_size_default_on_all_devices: "Legyen ez az alapértelmezett szövegméret az összes eszközén"
allow_private_messages: "Engedélyezés a többi felhasználónak, hogy privát üzenetet küldjenek Önnek"
external_links_in_new_tab: "Az összes külső hivatkozás megnyitása új lapon"
@@ -1296,7 +1295,7 @@ hu:
options: "Beállítások"
navigation_section: "Navigáció"
navigation_section_instruction: "Amikor a navigációs menüben egy téma listában új vagy olvasatlan elemek vannak…"
link_to_filtered_list_checkbox_description: "Link a szűrt listához"
link_to_filtered_list_checkbox_description: "Hivatkozás a szűrt listához"
show_count_new_items_checkbox_description: "Az új elemek számának megjelenítése"
change: "módosítás"
featured_topic: "Kiemelt téma"
@@ -1417,25 +1416,25 @@ hu:
true {
{ UNREAD, plural,
=0 {}
one {Van <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a>}
other {Van <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a>}
one {<a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a>}
other {<a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a>}
}
{ NEW, plural,
=0 {}
one { és <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzeneteket {groupLink}}
other { és <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzeneteket {groupLink}}
one { és <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
other { és <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
}
}
false {
{ UNREAD, plural,
=0 {}
one { <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a> üzenet maradt, vagy böngésszen más üzenetekben {groupLink}}
other { <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a> üzenet maradt, vagy böngésszen más üzenetben {groupLink}}
one { <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
other { <a href="{basePath}/u/{username}/messages/group/{groupName}/unread"># olvasatlan</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
}
{ NEW, plural,
=0 {}
one { <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetekben {groupLink}}
other { <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetben {groupLink}}
one { <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
other { <a href="{basePath}/u/{username}/messages/group/{groupName}/new"># új</a> üzenet maradt, vagy böngésszen más üzenetek között, itt: {groupLink}}
}
}
other {}
@@ -1572,16 +1571,16 @@ hu:
passkey_successfully_created: "Siker! Az új passkey létrehozva."
rename_passkey_instructions: "Válasszon egy olyan passkey-t, amely könnyen azonosítható az Ön számára, például használja a jelszókezelőjének nevét."
name:
default: "Fő passkey"
default: "Fő jelkulcs"
save: "Mentés"
title: "Passkey"
short_description: "A passkey olyan jelszóhelyettesítő, amely biometrikusan (pl. érintés, arcazonosító) vagy az eszköz PIN-kódjával/jelszavával igazolják a személyazonosságot."
title: "Jelkulcsok"
short_description: "A jelkulcs olyan jelszóhelyettesítő, amely biometrikusan (például érintéssel, arcazonosítással) vagy az eszköz PIN-kódjával/jelszavával igazolja a személyazonosságát."
added_date: "Hozzáadva %{date}"
last_used_date: "Utoljára használt %{date}"
never_used: "Soha nem használt"
not_allowed_error: "A passkey regisztráció folyamat vagy lejárt, vagy megszakadt, vagy nem engedélyezett."
already_added_error: "Már regisztrálta ezt a passkey-t. Nem kell újraregisztrálnia."
confirm_button: "vagy használj passkey-t"
last_used_date: "Utoljára használve: %{date}"
never_used: "Sosem volt használva"
not_allowed_error: "A jelkulcs regisztrációs folyamata lejárt, megszakadt vagy nem engedélyezett."
already_added_error: "Már regisztrálta ezt a jelkulcsot. Nem kell újból regisztrálnia."
confirm_button: "vagy jelkulcs használata"
change_about:
title: "Névjegy módosítása"
error: "Hiba történt az érték módosításakor."
@@ -1601,18 +1600,18 @@ hu:
success_via_admin: "Küldtünk egy levelet a megadott e-mail-címre. A felhasználónak követnie kell a levélben szereplő megerősítési utasításokat."
success_staff: "Küldtünk egy levelet a jelenlegi e-mail-címére. Kövesse a megerősítési utasításokat."
back_to_preferences: "Vissza a beállításokhoz"
confirm_success: "Az e-mail címe frissítve lett."
confirm: "Megerősít"
confirm_success: "Az e-mail-címe frissítve lett."
confirm: "Megerősítés"
authorizing_new:
description: "Kérjük, erősítsd meg, hogy szeretnéd az e-mail címedet a következőre módosítani:"
description_add: "Kérjük, erősítsd meg, hogy alternatív e-mail címet szeretnél hozzáadni:"
description: "Erősítse meg, hogy az e-mail-címét a következőre módosítja:"
description_add: "Erősítse meg, hogy egy alternatív e-mail-címet ad hozzá:"
authorizing_old:
title: "Régi email cím ellenőrzése"
description: "Kérjük, ellenőrizze a régi e-mail címét, ha folytatni szeretné az e-mail cím módosítását:"
description_add: "Kérjük, igazolja meglévő e-mail címét egy másik cím hozzáadásának folytatásához:"
old_email: "Régi e-mail: %{email}"
new_email: "Új e-mail: %{email}"
confirm_success: "Küldtünk egy e-mailt az új e-mail címére, hogy megerősítsük a változást!"
title: "Régi e-mail-cím ellenőrzése"
description: "Ellenőrizze a régi e-mail-címét, ha folytatni szeretné az e-mail-cím módosítását:"
description_add: "Ellenőrizze a meglévő e-mail-címét, ha folytatni szeretné az alternatív e-mail-cím hozzáadását:"
old_email: "Régi e-mail-cím: %{email}"
new_email: "Új e-mail-cím: %{email}"
confirm_success: "Küldtünk egy e-mailt az új e-mail-címére a változtatás megerősítéséhez."
change_avatar:
title: "Profilkép megváltoztatása"
gravatar: "<a href='//%{gravatarBaseUrl}%{gravatarLoginUrl}' target='_blank'>%{gravatarName}</a>, ez alapján:"
@@ -1642,7 +1641,7 @@ hu:
primary_label: "elsődleges"
unconfirmed_label: "nem megerősített"
resend_label: "megerősítő e-mail újraküldése"
resending_label: "küldés..."
resending_label: "küldés"
resent_label: "e-mail elküldve"
update_email: "E-mail-cím módosítása"
set_primary: "Elsődleges e-mail-cím beállítása"
@@ -1673,7 +1672,7 @@ hu:
account_specific: "Az Ön „%{account_description}” %{provider}-fiókja lesz használva a hitelesítéshez."
generic: "Az Ön %{provider}-fiókját fogja használni a hitelesítéshez."
activate_account:
action: "Kattintson ide a felhasználói fiókja aktiválásához"
action: "Kattintson ide a fiókja aktiválásához"
already_done: "Ez a fiók megerősítési hivatkozás már nem érvényes. Lehet, hogy a fiókja már aktiválva lett?"
please_continue: "Megerősítettük a fiókját, most visszairányítjuk a kezdőoldalra."
continue_button: "Befejezés!"
@@ -1894,8 +1893,8 @@ hu:
update_invite: "Frissítés"
update_invite_and_send_email: "Frissítés és e-mail küldése"
cancel: "Mégse"
create_link: "Link létrehozása"
create_link_and_send_email: "Link létrehozása és e-mail küldése"
create_link: "Hivatkozás létrehozása"
create_link_and_send_email: "Hivatkozás létrehozása és e-mail küldése"
invite_saved_without_sending_email: "Meghívó mentve. Másolja ki az alábbi linket, és ossza meg, hogy azonnal hozzáférést biztosítson ehhez az oldalhoz."
invite_saved_with_sending_email: "A meghívó e-mail elküldve. Az alábbi linket is kimásolhatja és megoszthatja, hogy azonnal hozzáférést biztosítson ehhez az oldalhoz."
bulk_invite:
@@ -1932,7 +1931,7 @@ hu:
one: "Legalább %{count} karakter"
other: "Legalább %{count} karakter"
required: "Adjon meg egy jelszót"
confirm: "Megerősít"
confirm: "Megerősítés"
incorrect_password: "A megadott jelszó helytelen."
summary:
title: "Összefoglaló"
@@ -2024,13 +2023,13 @@ hu:
presence_toggle:
online: "Online"
offline: "Offline"
title: "Jelenléti funkciók kapcsolása"
title: "Jelenléti funkciók be/ki"
user_tips:
button: "Értem!"
skip: "Tippek kihagyása"
first_notification:
title: "Az első értesítésed!"
content: "Az értesítések arra szolgálnak, hogy naprakészen tájékoztassuk Önt arról, hogy mi történik a közösségben."
title: "Az első értesítése!"
content: "Az értesítések arra szolgálnak, hogy naprakész legyen a közösségben zajló eseményekről."
topic_timeline:
title: "Téma idővonala"
content: "A téma idővonalával gyorsan lapozhat a hosszú témák között."
@@ -2038,10 +2037,10 @@ hu:
title: "Bejegyzés menü"
content: "Nézd meg, hogyan tudsz még interakcióba lépni a bejegyzéssel, ha a három pontra kattintasz!"
topic_notification_levels:
title: "Követed ezt a témát"
title: "Követi ezt a témát"
content: "Keresd ezt a csengőt, hogy beállíthasd az értesítéseket bizonyos témákhoz vagy egész kategóriákhoz."
suggested_topics:
title: "Olvass tovább!"
title: "Olvasson tovább!"
content: "Íme néhány téma, amelyet szerintünk szívesen elolvasna legközelebb."
loading: "Betöltés…"
errors:
@@ -2073,7 +2072,7 @@ hu:
dirty_form: "A változások nem lettek mentve! Biztos hogy el akarja hagyni a területet?"
errors:
required: "Kötelező"
invalid_url: "Érvényes URL-nek kell lennie"
invalid_url: "Érvényes webcímnek kell lennie"
not_an_integer: "Egész számnak kell lennie"
not_accepted: "Elfogadottnak kell lennie"
not_a_number: "Egy számnak kell lennie"
@@ -2083,8 +2082,8 @@ hu:
one: "Legfeljebb %{count} karakterből állhat"
other: "Legfeljebb %{count} karakterből állhat"
too_short:
one: "Nem lehet rövidebb, mint %{count} karakter"
other: "Nem lehet rövidebb, mint %{count} karakter"
one: "Legalább %{count} karakteresnek kell lennie"
other: "Legalább %{count} karakteresnek kell lennie"
close: "Bezárás"
assets_changed_confirm: "Ez az oldal most kapott egy szoftverfrissítést. Beszerzi most a legújabb verziót?"
logout: "Kijelentkezett."
@@ -2095,40 +2094,40 @@ hu:
login_disabled: "A belépés le van tiltva, amíg az oldal írásvédett módban van."
logout_disabled: "A kilépés le van tiltva, amíg az oldal írásvédett módban van."
staff_writes_only_mode:
enabled: "Ez az oldal csak a munkatársaknak van fenntartva. Továbbra is böngészheted, de a válaszadás és egyéb műveletek csak a munkatársak számára elérhetők."
enabled: "Ez a webhely „csak stáb” módban van. Továbbra is böngészheti, de a válaszadás, a kedvelés és az egyéb műveletek csak a stábtagok számára érhetők el."
logs_error_rate_notice:
reached_hour_MF: |
<b>{relativeAge}</b> <a href="{url}" target="_blank">{ rate, plural,
one {# hiba/óránként}
other {# hiba/óránként}
}</a> az oldalon meghatározott limit elérve {limit, plural,
one {# hiba/óránként}
other {# hiba/óránként}
}.
one {# hiba/óra,}
other {# hiba/óra}
}</a>, a webhelyen meghatározott {limit, plural,
one {# hiba/órás}
other {# hiba/órás}
} korlát elérve.
reached_minute_MF: |
<b>{relativeAge}</b> <a href="{url}" target="_blank">{ rate, plural,
one {# hiba/percenként}
other {# hiba/percenként}
}</a> az oldalon meghatározott limit elérve { limit, plural,
one {# hiba/percenként}
other {# hiba/percenként}
}.
one {# hiba/perc,}
other {# hiba/perc}
}</a>, a webhelyen meghatározott {limit, plural,
one {# hiba/perces}
other {# hiba/perces}
} korlát elérve.
exceeded_hour_MF: |
<b>{relativeAge}</b> <a href="{url}" target="_blank">{ rate, plural,
one {# hiba/óránként}
other {# hiba/óránként}
}</a> az olalon meghatározott limit túllépve{ limit, plural,
one {# hiba/óránként}
other {# hiba/óránként}
}.
one {# hiba/óra,}
other {# hiba/óra}
}</a>, a webhelyen meghatározott {limit, plural,
one {# hiba/órás}
other {# hiba/órás}
} korlát túllépve.
exceeded_minute_MF: |
<b>{relativeAge}</b> <a href="{url}" target="_blank">{ rate, plural,
one {# hiba/percenként}
other {# hiba/percenként}
}</a> az oldalon meghatározott limit túllépve { limit, plural,
one {# hiba/percenként}
other {# hiba/percenként}
}.
one {# hiba/perc,}
other {# hiba/perc}
}</a>, a webhelyen meghatározott {limit, plural,
one {# hiba/perces}
other {# hiba/perces}
} korlát túllépve.
learn_more: "További információ…"
learn_more_with_link: "<a href='%{url}' target='_blank'>További információ…</a>"
mute: Némítás
@@ -2326,7 +2325,7 @@ hu:
title: "Bejelentkezés Linkedln-nel"
sr_title: "Bejelentkezés Linkedln-nel"
passkey:
name: "Bejelentkezés passkey-el"
name: "Bejelentkezés jelkulccsal"
second_factor_toggle:
totp: "Helyette hitelesítő alkalmazás használata"
backup_code: "Helyette biztonsági kód használata"
@@ -2365,7 +2364,7 @@ hu:
full_name_requirement:
required_at_signup: "Kötelező"
optional_at_signup: "Nem kötelező"
hidden_at_signup: "Opcionális, regisztrációkor rejtve"
hidden_at_signup: "Nem kötelező, regisztrációkor rejtve"
shortcut_modifier_key:
shift: "Shift"
ctrl: "Ctrl"
@@ -2384,12 +2383,12 @@ hu:
delete_item: "%{name} törlése"
filter_by: "Szűrő: %{name}"
select_to_filter: "Válassza ki a szűrni kívánt értéket"
default_header_text: Kiválaszt...
default_header_text: Kiválasztás…
no_content: Nem található egyezés
results_count:
one: "%{count} találat"
other: "%{count} találat"
filter_placeholder: Keresés...
filter_placeholder: Keresés
filter_placeholder_with_any: Keresés vagy létrehozás…
create: "Létrehozás: „%{content}”"
max_content_reached:
@@ -2399,7 +2398,7 @@ hu:
one: "Válasszon legalább %{count} elemet."
other: "Válasszon legalább %{count} elemet."
components:
filter_for_more: További szűrés...
filter_for_more: Szűrés a továbbiakhoz…
categories_admin_dropdown:
title: "Kategóriák kezelése"
bulk_select_topics_dropdown:
@@ -2448,10 +2447,10 @@ hu:
add_warning: "Ez egy hivatalos figyelmeztetés."
toggle_whisper: "Suttogás be/ki"
toggle_unlisted: "Nem listázott állapot be/ki"
insert_table: "Tábla beillesztése"
insert_table: "Tábla beszúrása"
posting_not_on_topic: "Melyik témára szeretne válaszolni?"
saved_local_draft_tip: "helyben mentett"
similar_topics: "A témája hasonlít ehhez..."
similar_topics: "A témája hasonlít ehhez"
drafts_offline: "vázlatok offline"
edit_conflict: "szerkesztési ütközés"
esc: "Esc"
@@ -2524,7 +2523,7 @@ hu:
saving: "Mentés…"
saved: "Mentve!"
saved_draft: "Vázlat közzététele folyamatban. Koppintson a folytatáshoz."
uploading: "Feltöltés..."
uploading: "Feltöltés"
show_preview: "előnézet megjelenítése"
hide_preview: "előnézet elrejtése"
quote_post_title: "Teljes bejegyzés idézése"
@@ -2607,7 +2606,7 @@ hu:
title: "Képleírás hozzáadása"
image_scale_button: "Kép méretezése %{percent}%-ra"
delete_image_button: Kép törlése
toggle_image_grid: Képrács átkapcsolása
toggle_image_grid: Képrács be/ki
notifications:
tooltip:
regular:
@@ -2644,20 +2643,20 @@ hu:
liked: "<span>%{username}</span> %{description}"
liked_2: "<span class='double-user'>%{username}, %{username2}</span> %{description}"
liked_many:
one: "<span class='multi-user'>%{username} és %{count} a többiek</span>%{description}"
other: "<span class='multi-user'>%{username} és %{count} a többiek</span>%{description}"
one: "<span class='multi-user'>%{username} és még %{count} felhasználó</span>%{description}"
other: "<span class='multi-user'>%{username} és még %{count} felhasználó</span>%{description}"
liked_by_2_users: "%{username}, %{username2}"
liked_by_multiple_users:
one: "%{username} és még %{count} további"
other: "%{username} és még %{count} további"
one: "%{username} és még %{count} felhasználó"
other: "%{username} és még %{count} felhasználó"
liked_consolidated_description:
one: "kedvelte %{count} bejegyzését"
other: "kedvelte %{count} bejegyzését"
liked_consolidated: "<span>%{username}</span> %{description}"
linked_consolidated_description:
one: "%{count} bejegyzése linkelve"
other: "%{count} bejegyzése linkelve"
linked_consolidated: "<span>%{username}</span>%{description}"
one: "%{count} bejegyzése hivatkozva"
other: "%{count} bejegyzése hivatkozva"
linked_consolidated: "<span>%{username}</span> %{description}"
private_message: "<span>%{username}</span> %{description}"
invited_to_private_message: "<p><span>%{username}</span> %{description}"
invited_to_topic: "<span>%{username}</span> %{description}"
@@ -4680,6 +4679,10 @@ hu:
no_results:
title: "Nincs eredmény"
description: 'Nem találtunk semmit ami ennek megfelelne: ''%{filter}''.<br><br>Szeretné <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}"> felkeresni a webhely beállításaiban</a> vagy <a class="sidebar-additional-filter-users" href="%{user_list_filter_url}"> az adminisztátori listában?</a>'
footer:
interface_color_selector:
light: "Világos"
dark: "Sötét"
welcome_topic_banner:
title: "Hozzon létre üdvözlő témát"
description: "Az üdvözlő téma az első dolog, amit az új tagok elolvasnak. Gondoljon rá úgy, mint egy \"lendületbe hozó beszéd\"-re vagy \"küldetésnyilatkozat\"-ra. Tudassa mindenkivel, kiknek szól ez a közösség, mire számíthatnak itt, és mit szeretne, mit csináljanak először."
@@ -5401,8 +5404,6 @@ hu:
community_title: "Közösségi cím"
community_title_help: "A böngésző lapon látható rövid leírás a kulcsfontosságú oldalakhoz, például kategóriákhoz és témalistákhoz."
banner_image: "Banner kép"
banner_image_help: |
Ezt a Rólunk oldaladon fogod használni. Ajánlott méret: 1100x300px. Elfogadott típusok: JPG, PNG és SVG, legfeljebb 10MB.
contact_information: "Elérhetőség"
community_owner: "Közösség tulajdonosa"
community_owner_placeholder: "Johnny Smith"
@@ -6638,8 +6639,6 @@ hu:
other: "Nem lehet törölni az összes hozzászólást, mert a felhasználónak több mint %{count} hozzászólása van. (delete_all_posts_max)"
delete_confirm_title: "Biztosan törli ezt a felhasználót? Ez végleges!"
delete_confirm: "Általában előnyösebb a felhasználók anonimizálása, mint a törlésük, hogy elkerüljük a meglévő viták tartalmának eltávolítását."
delete_and_block: "Az e-mail és az IP-cím törlése és <b>blokkolása</b>"
delete_dont_block: "Csak törlés"
deleting_user: "Felhasználó törlése"
deleted: "A felhasználó el lett távolítva"
delete_failed: "Hiba történt a felhasználó törlésekor. Mielőtt megpróbálná törölni a felhasználót, győződjön meg arról, hogy az összes bejegyzést törölte."

View File

@@ -458,8 +458,6 @@ hy:
confirm: "Դուք արդեն ունեք սևագիր: Ի՞նչ կցանկանայիք անել դրա հետ:"
yes_value: "Ջնջել"
no_value: "Վերսկսել խմբագրումը"
dropdown:
view_all: "դիտել բոլոը"
topic_count_all:
one: "Տեսնել %{count} նոր թեման"
other: "Դիտել %{count} նոր թեմաները"
@@ -3781,6 +3779,10 @@ hy:
content: "Վերանայում"
invite:
content: "Հրավիրել"
footer:
interface_color_selector:
light: "Բաց"
dark: "Մութ"
form_templates:
upload_field:
upload: "Վերբեռնել"
@@ -4901,8 +4903,6 @@ hy:
cant_delete_all_too_many_posts:
one: "Հնարավոր չէ ջնջել բոլոր գրառումները, քանի որ օգտատերն ունի ավելի քան %{count} գրառում: (delete_all_posts_max)"
other: "Հնարավոր չէ ջնջել բոլոր գրառումները, քանի որ օգտատերն ունի ավելի քան %{count} գրառում: (delete_all_posts_max)"
delete_and_block: "Ջնջել և <b>արգելափակել</b> այս էլ. և IP հասցեները:"
delete_dont_block: "Միայն ջնջել "
deleted: "Օգտատերը ջնջված է:"
delete_failed: "Այդ օգտատիրոջը ջնջելիս տեղի է ունեցել սխալ: Համոզվեք, որ բոլոր գրառումները ջնջված են՝ մինչ օգտատիրոջը ջնջել փորձելը:"
send_activation_email: "Ուղարկել Ակտիվացիայի Էլ. Նամակ"

View File

@@ -2719,7 +2719,6 @@ id:
cancel: "Batal"
confirmation:
cancel: "Batal"
delete_and_block: "Hapus dan <b>block</b> email dan alamat IP ini"
reset_bounce_score:
label: "Reset"
suspend_modal_title: "Tangguhkan Pengguna"

View File

@@ -463,7 +463,6 @@ it:
dropdown:
title: "Apri il menu delle ultime bozze"
untitled: "Bozza senza titolo"
view_all: "visualizza tutto"
other_drafts:
one: "+%{count} altra bozza"
other: "+%{count} altre bozze"
@@ -4673,6 +4672,10 @@ it:
no_results:
title: "Nessun risultato"
description: 'Nessuna corrispondenza trovata per "%{filter}":<br><br> Vuoi <a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">cercare tra le impostazioni del sito</a> o nell''<a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">elenco degli utenti amministratori</a>?'
footer:
interface_color_selector:
light: "Chiaro"
dark: "Scuro"
welcome_topic_banner:
title: "Crea il tuo argomento di benvenuto"
description: "Il tuo argomento di benvenuto è la prima cosa che leggeranno i nuovi membri. Consideralo come un \"discorso fatto in ascensore\" o una \"dichiarazione di intenti\". Fai sapere a tutti a chi si rivolge questa community, cosa possono aspettarsi di trovare qui e cosa vorresti che facessero prima."
@@ -5396,8 +5399,6 @@ it:
community_title: "Titolo della community"
community_title_help: "Breve descrizione, mostrata nella scheda del browser, per pagine chiave come categorie ed elenchi di argomenti."
banner_image: "Immagine banner"
banner_image_help: |
Verrà mostrato sulla tua pagina Informazioni. Dimensioni consigliate: 1100x300px. Formati supportati: JPG, PNG e SVG fino a 10 MB.
contact_information: "Informazioni di contatto"
community_owner: "Proprietario della comunità"
community_owner_placeholder: "Mario Rossi"
@@ -6627,8 +6628,6 @@ it:
other: "Impossibile cancellare tutti i messaggi perché l'utente ha più di %{count} messaggi. (delete_all_posts_max.)"
delete_confirm_title: "Vuoi davvero eliminare questo utente? Questa operazione è irreversibile!"
delete_confirm: "In genere è preferibile rendere anonimi gli utenti piuttosto che eliminarli, per evitare di rimuoverne i contenuti dalle discussioni esistenti."
delete_and_block: "Elimina e <b>blocca</b> questa email e indirizzo IP"
delete_dont_block: "Elimina soltanto"
deleting_user: "Cancellazione utente…"
deleted: "L'utente è stato cancellato."
delete_failed: "Si è verificato un errore nella cancellazione dell'utente. Assicurati che tutti i messaggi siano stati cancellati prima di provare a cancellare l'utente."

View File

@@ -414,7 +414,6 @@ ja:
dropdown:
title: "最新の下書きメニューを開く"
untitled: "無題の下書き"
view_all: "すべて表示"
other_drafts:
other: "他 %{count} 件の下書き"
topic_count_all:
@@ -4419,6 +4418,10 @@ ja:
no_results:
title: "結果がありません"
description: '%{filter} に一致するものは見つかりませんでした。<br><br><a class="sidebar-additional-filter-settings" href="%{settings_filter_url}">サイト設定</a>または<a class="sidebar-additional-filter-users" href="%{user_list_filter_url}">管理者ユーザーリストを検索</a>しますか?'
footer:
interface_color_selector:
light: "ライト"
dark: "ダーク"
welcome_topic_banner:
title: "ウェルカムトピックを作成しましょう"
description: "ウェルカムトピックは、新しいメンバーが最初に読むものです。「エレベーターピッチ」や「ミッションステートメント」と考えると良いでしょう。このコミュニティーの対象者、ここで期待できること、最初にしてほしいことを伝えましょう。"
@@ -5126,8 +5129,6 @@ ja:
community_title: "コミュニティーのタイトル"
community_title_help: "ブラウザのタブに表示される、カテゴリやトピックリストなどの主要ページの短い説明です。"
banner_image: "バナー画像"
banner_image_help: |
これは情報ページで使用されます。推奨サイズ: 1100x300px。許容される形式: 10MB 以下の JPG、PNG、SVG。
contact_information: "連絡先情報"
community_owner: "コミュニティーオーナー"
community_owner_placeholder: "ジョニー・スミス"
@@ -5730,7 +5731,7 @@ ja:
no_result: "要約の結果は見つかりませんでした。"
reply_key: "返信キー"
post_link_with_smtp: "投稿と SMTP の詳細"
skipped_reason: "スキップの理由"
skipped_reason: "理由をスキップ"
incoming_emails:
from_address: "送信者"
to_addresses: "宛先"
@@ -6341,8 +6342,6 @@ ja:
other: "すべての投稿を削除することはできませんでした。ユーザーは %{count} 件以上投稿しています。(delete_all_posts_max)"
delete_confirm_title: "このユーザーを削除してもよろしいですか?永久に削除されます!"
delete_confirm: "一般に、ユーザーを削除するのではなく、匿名化して既存のディスカッションからコンテンツを削除しないようにするのが推奨されます。"
delete_and_block: "このメールと IP アドレスを削除して<b>ブロック</b>する"
delete_dont_block: "削除のみ"
deleting_user: "ユーザーを削除中…"
deleted: "ユーザーが削除されました。"
delete_failed: "ユーザーを削除中にエラーが発生しました。このユーザーのすべての投稿を削除したことを確認してから、ユーザーを削除してください。"

View File

@@ -327,8 +327,6 @@ ko:
abandon:
yes_value: "버리기"
no_value: "편집 재개"
dropdown:
view_all: "모두 보기"
topic_count_all:
other: "%{count}개의 새로운 글 보기"
topic_count_categories:
@@ -3576,6 +3574,10 @@ ko:
filter: "필터..."
no_results:
title: "결과 없음"
footer:
interface_color_selector:
light: "라이트"
dark: "다크"
welcome_topic_banner:
title: "환영 글 만들기"
button_title: "편집 시작"
@@ -4825,8 +4827,6 @@ ko:
other: "모든 게시물을 삭제할 수 없습니다. 일부 게시물은 %{count}일 이전에 작성되었습니다. (delete_user_max_post_age 설정)"
cant_delete_all_too_many_posts:
other: "이 사용자는 %{count}개 이상의 게시물을 보유하고 있기 때문에 모든 게시물을 삭제할 수 없습니다. (delete_all_posts_max)"
delete_and_block: "이 이메일과 IP 주소를 삭제하고 <b>차단</b>"
delete_dont_block: "삭제만 하기"
deleted: "사용자가 삭제되었습니다."
delete_failed: "이 사용자를 삭제하는 중에 오류가 발생했습니다. 사용자를 삭제하기 전에 모든 게시물을 삭제해야 합니다."
send_activation_email: "활성화 이메일 전송"

View File

@@ -3623,6 +3623,10 @@ lt:
invite:
content: "Kviesti"
filter: "Filtruoti..."
footer:
interface_color_selector:
light: "Šviesi"
dark: "Tamsi"
until: "Iki:"
form_templates:
upload_field:
@@ -4760,8 +4764,6 @@ lt:
few: "Negalima ištrinti visų įrašų, nes vartotojas turi daugiau nei %{count} įrašus. (delete_all_posts_max)"
many: "Negalima ištrinti visų įrašų, nes vartotojas turi daugiau nei %{count} įrašus. (delete_all_posts_max)"
other: "Negalima ištrinti visų įrašų, nes vartotojas turi daugiau nei %{count} įrašus. (delete_all_posts_max)"
delete_and_block: "Ištrinti ir <b>užblokuoti</b> šį el. paštą ir IP adresą"
delete_dont_block: "Tik Ištrinti"
deleted: "Šis vartotojas buvo ištrintas."
delete_failed: "Įvyko klaida ištrinant vartotoją. Įsitikinkite, kad visi pranešimai buvo ištrinti prieš trinant vartotoją."
send_activation_email: "Siųsti aktyvacijos el. laišką"

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