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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions app/validators/language_switcher_setting_validator.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class LanguageSwitcherSettingValidator
def initialize(opts = {})
@opts = opts
end

def valid_value?(val)
return true if val == "f"
SiteSetting.set_locale_from_cookie
end

def error_message
I18n.t("site_settings.errors.set_locale_cookie_requirements")
end
end
64 changes: 64 additions & 0 deletions assets/javascripts/discourse/components/language-switcher.gjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import Component from "@glimmer/component";
import { fn } from "@ember/helper";
import { action } from "@ember/object";
import { service } from "@ember/service";
import DButton from "discourse/components/d-button";
import DropdownMenu from "discourse/components/dropdown-menu";
import cookie from "discourse/lib/cookie";
import DMenu from "float-kit/components/d-menu";

export default class LanguageSwitcher extends Component {
@service site;
@service siteSettings;
@service router;

get localeOptions() {
return JSON.parse(this.siteSettings.available_locales).map(
({ name, value }) => {
return {
label: name,
value,
};
}
);
}

@action
async changeLocale(locale) {
cookie("locale", locale);
this.dMenu.close();
// we need a hard refresh here for the locale to take effect
window.location.reload();
}

@action
onRegisterApi(api) {
this.dMenu = api;
}

<template>
<DMenu
@identifier="discourse-translator_language-switcher"
title="Language switcher"
@icon="language"
class="btn-flat btn-icon icon"
@onRegisterApi={{this.onRegisterApi}}
>
<:content>
<DropdownMenu as |dropdown|>
{{#each this.localeOptions as |option|}}
<dropdown.item
class="discourse-translator_locale-option"
data-menu-option-id={{option.value}}
>
<DButton
@translatedLabel={{option.label}}
@action={{fn this.changeLocale option.value}}
/>
</dropdown.item>
{{/each}}
</DropdownMenu>
</:content>
</DMenu>
</template>
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,31 @@
import { ajax } from "discourse/lib/ajax";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { withSilencedDeprecations } from "discourse/lib/deprecated";
import { withPluginApi } from "discourse/lib/plugin-api";
import { withSilencedDeprecations } from "discourse-common/lib/deprecated";
import { i18n } from "discourse-i18n";
import LanguageSwitcher from "../components/language-switcher";
import ToggleTranslationButton from "../components/post-menu/toggle-translation-button";
import TranslatedPost from "../components/translated-post";

function initializeTranslation(api) {
const siteSettings = api.container.lookup("service:site-settings");
if (!siteSettings.translator_enabled) {
return;
}

const currentUser = api.getCurrentUser();

if (!currentUser || !siteSettings.translator_enabled) {
return;
if (!currentUser && siteSettings.experimental_anon_language_switcher) {
api.headerIcons.add(
"discourse-translator_language-switcher",
LanguageSwitcher,
{ before: ["search"] }
);
}

customizePostMenu(api);
if (currentUser) {
customizePostMenu(api);
}
}

function customizePostMenu(api, container) {
Expand Down Expand Up @@ -123,24 +134,6 @@ function customizeWidgetPostMenu(api) {
post.set("translated_text", "");
}
});

api.addPostMenuButton("translate", (attrs, state) => {
if (!attrs.can_translate) {
return;
}

const [action, title] = !state.isTranslated
? ["translate", "translator.view_translation"]
: ["hideTranslation", "translator.hide_translation"];

return {
action,
title,
icon: "globe",
position: "first",
className: state.isTranslated ? "translated" : null,
};
});
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh yikes! It's not perfect, this was accidentally removed. Will add it back.

}

export default {
Expand Down
4 changes: 4 additions & 0 deletions assets/stylesheets/common/common.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[data-identifier="discourse-translator_language-switcher"]
.fk-d-menu__inner-content {
max-height: 50vh;
}
3 changes: 3 additions & 0 deletions config/locales/server.en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ en:
translator_azure_custom_subdomain: "Required if using a Virtual Network or Firewall for Azure Cognitive Services. Note: Only enter the custom subdomain not the full custom endpoint."
restrict_translation_by_group: "Only allowed groups can translate"
restrict_translation_by_poster_group: "Only allow translation of posts made by users in allowed groups. If empty, allow translations of posts from all users."
experimental_anon_language_switcher: "Enable experimental language switcher for anonymous users. This will allow anonymous users to switch between translated versions of Discourse and user-contributed content in topics."
errors:
set_locale_cookie_requirements: "The experimental language switcher for anonymous users requires the `set locale from cookie` site setting to be enabled."
translator:
failed: "The translator is unable to translate this content (%{source_locale}) to the default language of this site (%{target_locale})."
not_supported: "This language is not supported by the translator."
Expand Down
4 changes: 4 additions & 0 deletions config/settings.yml
Original file line number Diff line number Diff line change
Expand Up @@ -102,3 +102,7 @@ discourse_translator:
default: ""
client: true
type: group_list
experimental_anon_language_switcher:
default: false
client: true
validator: "LanguageSwitcherSettingValidator"
1 change: 1 addition & 0 deletions plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

enabled_site_setting :translator_enabled
register_asset "stylesheets/common/post.scss"
register_asset "stylesheets/common/common.scss"

module ::DiscourseTranslator
PLUGIN_NAME = "discourse-translator".freeze
Expand Down
5 changes: 5 additions & 0 deletions spec/services/base_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,11 @@ class EmptyTranslator < DiscourseTranslator::Base
post.cooked = text
expect(DiscourseTranslator::Base.text_for_detection(post)).to eq(text)
end

it "strips text before truncation" do
post.cooked = "<img src='http://example.com/image.png' />" + "a" * 1000
expect(DiscourseTranslator::Base.text_for_detection(post)).to eq("a" * 1000)
end
end

describe ".text_for_translation" do
Expand Down
28 changes: 28 additions & 0 deletions spec/system/anon_language_switcher_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

RSpec.describe "Anonymous user language switcher", type: :system do
fab!(:japanese_user) { Fabricate(:user, locale: "ja") }
it "shows the correct language based on the selected language and login status" do
SWITCHER_SELECTOR = "button[data-identifier='discourse-translator_language-switcher']"

visit("/")
expect(page).not_to have_css(SWITCHER_SELECTOR)

SiteSetting.translator_enabled = true
SiteSetting.allow_user_locale = true
SiteSetting.set_locale_from_cookie = true
SiteSetting.experimental_anon_language_switcher = true
visit("/")
expect(page).to have_css(SWITCHER_SELECTOR)
expect(find(".nav-item_latest")).to have_content("Latest")

switcher = PageObjects::Components::DMenu.new(SWITCHER_SELECTOR)
switcher.expand
switcher.click_button("Español")
expect(find(".nav-item_latest")).to have_content("Recientes")

sign_in(japanese_user)
visit("/")
expect(find(".nav-item_latest")).to have_content("最新")
end
end
Loading