diff --git a/app/assets/javascripts/admin/components/admin-report.js.es6 b/app/assets/javascripts/admin/components/admin-report.js.es6 index feab25677b..a29b627f41 100644 --- a/app/assets/javascripts/admin/components/admin-report.js.es6 +++ b/app/assets/javascripts/admin/components/admin-report.js.es6 @@ -41,7 +41,7 @@ export default Ember.Component.extend({ classNameBindings: ["isEnabled", "isLoading", "dasherizedDataSourceName"], classNames: ["admin-report"], isEnabled: true, - disabledLabel: "admin.dashboard.disabled", + disabledLabel: I18n.t("admin.dashboard.disabled"), isLoading: false, rateLimitationString: null, dataSourceName: null, diff --git a/app/assets/javascripts/admin/controllers/admin-dashboard-next-general.js.es6 b/app/assets/javascripts/admin/controllers/admin-dashboard-next-general.js.es6 index 2de7b16f16..f229ef7640 100644 --- a/app/assets/javascripts/admin/controllers/admin-dashboard-next-general.js.es6 +++ b/app/assets/javascripts/admin/controllers/admin-dashboard-next-general.js.es6 @@ -22,6 +22,7 @@ export default Ember.Controller.extend(PeriodComputationMixin, { "model.attributes.last_backup_taken_at" ), shouldDisplayDurability: Ember.computed.and("diskSpace"), + basePath: Discourse.BaseUri, @computed activityMetrics() { @@ -77,6 +78,13 @@ export default Ember.Controller.extend(PeriodComputationMixin, { }; }, + @computed + trendingSearchDisabledLabel() { + return I18n.t("admin.dashboard.reports.trending_search.disabled", { + basePath: Discourse.BaseUri + }); + }, + usersByTypeReport: staticReport("users_by_type"), usersByTrustLevelReport: staticReport("users_by_trust_level"), diff --git a/app/assets/javascripts/admin/templates/components/admin-report.hbs b/app/assets/javascripts/admin/templates/components/admin-report.hbs index fb24af76c3..653feeadcc 100644 --- a/app/assets/javascripts/admin/templates/components/admin-report.hbs +++ b/app/assets/javascripts/admin/templates/components/admin-report.hbs @@ -192,6 +192,6 @@ {{/conditional-loading-section}} {{else}}
- {{{i18n disabledLabel}}} + {{{disabledLabel}}}
{{/if}} diff --git a/app/assets/javascripts/admin/templates/dashboard_next_general.hbs b/app/assets/javascripts/admin/templates/dashboard_next_general.hbs index 682b6831c7..75c24cf946 100644 --- a/app/assets/javascripts/admin/templates/dashboard_next_general.hbs +++ b/app/assets/javascripts/admin/templates/dashboard_next_general.hbs @@ -161,8 +161,8 @@ reportOptions=trendingSearchOptions filters=trendingSearchFilters isEnabled=logSearchQueriesEnabled - disabledLabel="admin.dashboard.reports.trending_search.disabled"}} - {{{i18n "admin.dashboard.reports.trending_search.more"}}} + disabledLabel=trendingSearchDisabledLabel}} + {{{i18n "admin.dashboard.reports.trending_search.more" basePath=basePath}}} diff --git a/app/assets/javascripts/discourse/components/suggested-topics.js.es6 b/app/assets/javascripts/discourse/components/suggested-topics.js.es6 index 7d2228af58..e95df8fe62 100644 --- a/app/assets/javascripts/discourse/components/suggested-topics.js.es6 +++ b/app/assets/javascripts/discourse/components/suggested-topics.js.es6 @@ -60,7 +60,8 @@ export default Ember.Component.extend({ NEW: newTopics, CATEGORY: category ? true : false, latestLink: opts.latestLink, - catLink: opts.catLink + catLink: opts.catLink, + basePath: "" }); } else if (category) { return I18n.t("topic.read_more_in_category", opts); diff --git a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 index 3d69c20713..127acb0bcb 100644 --- a/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 +++ b/app/assets/javascripts/discourse/controllers/forgot-password.js.es6 @@ -26,7 +26,9 @@ export default Ember.Controller.extend(ModalFunctionality, { help() { this.setProperties({ - offerHelp: I18n.t("forgot_password.help"), + offerHelp: I18n.t("forgot_password.help", { + basePath: Discourse.BaseUri + }), helpSeen: true }); }, diff --git a/app/assets/javascripts/discourse/models/topic-details.js.es6 b/app/assets/javascripts/discourse/models/topic-details.js.es6 index 6614a0ce03..c86b93f2ba 100644 --- a/app/assets/javascripts/discourse/models/topic-details.js.es6 +++ b/app/assets/javascripts/discourse/models/topic-details.js.es6 @@ -51,7 +51,8 @@ const TopicDetails = RestModel.extend({ return I18n.t("topic.notifications.reasons.mailing_list_mode"); } else { return I18n.t(localeString, { - username: Discourse.User.currentProp("username_lower") + username: Discourse.User.currentProp("username_lower"), + basePath: Discourse.BaseUri }); } }.property("notification_level", "notifications_reason_id"), diff --git a/app/jobs/scheduled/pending_flags_reminder.rb b/app/jobs/scheduled/pending_flags_reminder.rb index 817b735b1b..05ab123ad8 100644 --- a/app/jobs/scheduled/pending_flags_reminder.rb +++ b/app/jobs/scheduled/pending_flags_reminder.rb @@ -26,7 +26,7 @@ module Jobs archetype: Archetype.private_message, subtype: TopicSubtype.system_message, title: I18n.t('flags_reminder.subject_template', count: flagged_posts_count), - raw: mentions + I18n.t('flags_reminder.flags_were_submitted', count: SiteSetting.notify_about_flags_after) + raw: mentions + I18n.t('flags_reminder.flags_were_submitted', count: SiteSetting.notify_about_flags_after, base_path: Discourse.base_path) ) self.last_notified_id = flag_ids.max diff --git a/app/models/admin_dashboard_data.rb b/app/models/admin_dashboard_data.rb index 33d2c87858..565a61f620 100644 --- a/app/models/admin_dashboard_data.rb +++ b/app/models/admin_dashboard_data.rb @@ -123,7 +123,7 @@ class AdminDashboardData end def self.problem_message_check(i18n_key) - $redis.get(problem_message_key(i18n_key)) ? I18n.t(i18n_key) : nil + $redis.get(problem_message_key(i18n_key)) ? I18n.t(i18n_key, base_path: Discourse.base_path) : nil end def self.add_problem_message(i18n_key, expire_seconds = nil) @@ -188,19 +188,27 @@ class AdminDashboardData end def google_oauth2_config_check - I18n.t('dashboard.google_oauth2_config_warning') if SiteSetting.enable_google_oauth2_logins && (SiteSetting.google_oauth2_client_id.blank? || SiteSetting.google_oauth2_client_secret.blank?) + if SiteSetting.enable_google_oauth2_logins && (SiteSetting.google_oauth2_client_id.blank? || SiteSetting.google_oauth2_client_secret.blank?) + I18n.t('dashboard.google_oauth2_config_warning', base_path: Discourse.base_path) + end end def facebook_config_check - I18n.t('dashboard.facebook_config_warning') if SiteSetting.enable_facebook_logins && (SiteSetting.facebook_app_id.blank? || SiteSetting.facebook_app_secret.blank?) + if SiteSetting.enable_facebook_logins && (SiteSetting.facebook_app_id.blank? || SiteSetting.facebook_app_secret.blank?) + I18n.t('dashboard.facebook_config_warning', base_path: Discourse.base_path) + end end def twitter_config_check - I18n.t('dashboard.twitter_config_warning') if SiteSetting.enable_twitter_logins && (SiteSetting.twitter_consumer_key.blank? || SiteSetting.twitter_consumer_secret.blank?) + if SiteSetting.enable_twitter_logins && (SiteSetting.twitter_consumer_key.blank? || SiteSetting.twitter_consumer_secret.blank?) + I18n.t('dashboard.twitter_config_warning', base_path: Discourse.base_path) + end end def github_config_check - I18n.t('dashboard.github_config_warning') if SiteSetting.enable_github_logins && (SiteSetting.github_client_id.blank? || SiteSetting.github_client_secret.blank?) + if SiteSetting.enable_github_logins && (SiteSetting.github_client_id.blank? || SiteSetting.github_client_secret.blank?) + I18n.t('dashboard.github_config_warning', base_path: Discourse.base_path) + end end def s3_config_check @@ -208,8 +216,13 @@ class AdminDashboardData if !GlobalSetting.use_s3? bad_keys = (SiteSetting.s3_access_key_id.blank? || SiteSetting.s3_secret_access_key.blank?) && !SiteSetting.s3_use_iam_profile - return I18n.t('dashboard.s3_config_warning') if SiteSetting.enable_s3_uploads && (bad_keys || SiteSetting.s3_upload_bucket.blank?) - return I18n.t('dashboard.s3_backup_config_warning') if SiteSetting.backup_location == BackupLocationSiteSetting::S3 && (bad_keys || SiteSetting.s3_backup_bucket.blank?) + if SiteSetting.enable_s3_uploads && (bad_keys || SiteSetting.s3_upload_bucket.blank?) + return I18n.t('dashboard.s3_config_warning', base_path: Discourse.base_path) + end + + if SiteSetting.backup_location == BackupLocationSiteSetting::S3 && (bad_keys || SiteSetting.s3_backup_bucket.blank?) + return I18n.t('dashboard.s3_backup_config_warning', base_path: Discourse.base_path) + end end nil end @@ -220,7 +233,7 @@ class AdminDashboardData def failing_emails_check num_failed_jobs = Jobs.num_email_retry_jobs - I18n.t('dashboard.failing_emails_warning', num_failed_jobs: num_failed_jobs) if num_failed_jobs > 0 + I18n.t('dashboard.failing_emails_warning', num_failed_jobs: num_failed_jobs, base_path: Discourse.base_path) if num_failed_jobs > 0 end def subfolder_ends_in_slash_check @@ -233,7 +246,7 @@ class AdminDashboardData def email_polling_errored_recently errors = Jobs::PollMailbox.errors_in_past_24_hours - I18n.t('dashboard.email_polling_errored_recently', count: errors) if errors > 0 + I18n.t('dashboard.email_polling_errored_recently', count: errors, base_path: Discourse.base_path) if errors > 0 end def missing_mailgun_api_key @@ -245,7 +258,7 @@ class AdminDashboardData def force_https_check return unless @opts[:check_force_https] - I18n.t('dashboard.force_https_warning') unless SiteSetting.force_https + I18n.t('dashboard.force_https_warning', base_path: Discourse.base_path) unless SiteSetting.force_https end def out_of_date_themes diff --git a/app/models/invite.rb b/app/models/invite.rb index b613e22c5e..23f09dff2b 100644 --- a/app/models/invite.rb +++ b/app/models/invite.rb @@ -104,7 +104,7 @@ class Invite < ActiveRecord::Base if user = find_user_by_email(lower_email) extend_permissions(topic, user, invited_by) if topic - raise UserExists.new I18n.t("invite.user_exists", email: lower_email, username: user.username) + raise UserExists.new I18n.t("invite.user_exists", email: lower_email, username: user.username, base_path: Discourse.base_path) end invite = Invite.with_deleted diff --git a/app/models/post_action.rb b/app/models/post_action.rb index bf233bb4db..8442b196b4 100644 --- a/app/models/post_action.rb +++ b/app/models/post_action.rb @@ -626,7 +626,11 @@ class PostAction < ActiveRecord::Base options = { url: post.url, edit_delay: SiteSetting.cooldown_minutes_after_hiding_posts, - flag_reason: I18n.t("flag_reasons.#{post_action_type}", locale: SiteSetting.default_locale), + flag_reason: I18n.t( + "flag_reasons.#{post_action_type}", + locale: SiteSetting.default_locale, + base_path: Discourse.base_path + ) } Jobs.enqueue_in(5.seconds, :send_system_message, diff --git a/app/models/user.rb b/app/models/user.rb index 777dd6796e..97415261ca 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -952,7 +952,7 @@ class User < ActiveRecord::Base .where.not(post_id: disagreed_flag_post_ids) .each do |tl| begin - message = I18n.t('flag_reason.spam_hosts', domain: tl.domain) + message = I18n.t('flag_reason.spam_hosts', domain: tl.domain, base_path: Discourse.base_path) PostAction.act(Discourse.system_user, tl.post, PostActionType.types[:spam], message: message) rescue PostAction::AlreadyActed # If the user has already acted, just ignore it diff --git a/app/serializers/post_action_type_serializer.rb b/app/serializers/post_action_type_serializer.rb index 9ea2847e9a..ecb9d6ecff 100644 --- a/app/serializers/post_action_type_serializer.rb +++ b/app/serializers/post_action_type_serializer.rb @@ -32,11 +32,11 @@ class PostActionTypeSerializer < ApplicationSerializer end def description - i18n('description', tos_url: tos_path) + i18n('description', tos_url: tos_path, base_path: Discourse.base_path) end def short_description - i18n('short_description', tos_url: tos_path) + i18n('short_description', tos_url: tos_path, base_path: Discourse.base_path) end def name_key @@ -49,5 +49,4 @@ class PostActionTypeSerializer < ApplicationSerializer key = "post_action_types.#{name_key}.#{field}" vars ? I18n.t(key, vars) : I18n.t(key) end - end diff --git a/app/serializers/wizard_field_serializer.rb b/app/serializers/wizard_field_serializer.rb index 4a70098a57..72e5b07baa 100644 --- a/app/serializers/wizard_field_serializer.rb +++ b/app/serializers/wizard_field_serializer.rb @@ -27,8 +27,15 @@ class WizardFieldSerializer < ApplicationSerializer @i18n_key ||= "wizard.step.#{object.step.id}.fields.#{object.id}".underscore end + def translate(sub_key, vars = nil) + key = "#{i18n_key}.#{sub_key}" + return nil unless I18n.exists?(key) + + vars.nil? ? I18n.t(key) : I18n.t(key, vars) + end + def label - I18n.t("#{i18n_key}.label", default: '') + translate("label") end def include_label? @@ -36,7 +43,7 @@ class WizardFieldSerializer < ApplicationSerializer end def placeholder - I18n.t("#{i18n_key}.placeholder", default: '') + translate("placeholder") end def include_placeholder? @@ -44,7 +51,7 @@ class WizardFieldSerializer < ApplicationSerializer end def description - I18n.t("#{i18n_key}.description", default: '') + translate("description", base_path: Discourse.base_path) end def include_description? diff --git a/app/serializers/wizard_step_serializer.rb b/app/serializers/wizard_step_serializer.rb index 90f54a9178..0f9bccd4fa 100644 --- a/app/serializers/wizard_step_serializer.rb +++ b/app/serializers/wizard_step_serializer.rb @@ -31,8 +31,15 @@ class WizardStepSerializer < ApplicationSerializer @i18n_key ||= "wizard.step.#{object.id}".underscore end + def translate(sub_key, vars = nil) + key = "#{i18n_key}.#{sub_key}" + return nil unless I18n.exists?(key) + + vars.nil? ? I18n.t(key) : I18n.t(key, vars) + end + def description - I18n.t("#{i18n_key}.description", default: '') + translate("description", base_path: Discourse.base_path) end def include_description? @@ -40,7 +47,7 @@ class WizardStepSerializer < ApplicationSerializer end def title - I18n.t("#{i18n_key}.title", default: '') + translate("title") end def include_title? diff --git a/app/services/spam_rule/flag_sockpuppets.rb b/app/services/spam_rule/flag_sockpuppets.rb index b669e80a8a..e3df8a88f8 100644 --- a/app/services/spam_rule/flag_sockpuppets.rb +++ b/app/services/spam_rule/flag_sockpuppets.rb @@ -30,7 +30,7 @@ class SpamRule::FlagSockpuppets end def flag_sockpuppet_users - message = I18n.t('flag_reason.sockpuppet', ip_address: @post.user.ip_address) + message = I18n.t('flag_reason.sockpuppet', ip_address: @post.user.ip_address, base_path: Discourse.base_path) PostAction.act(Discourse.system_user, @post, PostActionType.types[:spam], message: message) rescue PostAction::AlreadyActed if (first_post = @post.topic.posts.by_post_number.first).try(:user).try(:new_user?) diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 34a146ce9b..609a635994 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -1179,7 +1179,7 @@ en: complete_username_not_found: "No account matches the username %{username}" complete_email_not_found: "No account matches %{email}" - help: "Email not arriving? Be sure to check your spam folder first.

Not sure which email address you used? Enter an email address and we’ll let you know if it exists here.

If you no longer have access to the email address on your account, please contact our helpful staff.

" + help: "Email not arriving? Be sure to check your spam folder first.

Not sure which email address you used? Enter an email address and we’ll let you know if it exists here.

If you no longer have access to the email address on your account, please contact our helpful staff.

" button_ok: "OK" button_help: "Help" @@ -1736,15 +1736,15 @@ en: UNREAD, plural, =0 {} one { - is 1 unread + is 1 unread } other { - are # unread + are # unread } } { NEW, plural, =0 {} - one { {BOTH, select, true{and } false {is } other{}} 1 new topic} - other { {BOTH, select, true{and } false {are } other{}} # new topics} + one { {BOTH, select, true{and } false {is } other{}} 1 new topic} + other { {BOTH, select, true{and } false {are } other{}} # new topics} } remaining, or {CATEGORY, select, true {browse other topics in {catLink}} false {{latestLink}} other {}}" browse_all_categories: Browse all categories @@ -1842,7 +1842,7 @@ en: "2_8": 'You will see a count of new replies because you are tracking this category.' "2_4": 'You will see a count of new replies because you posted a reply to this topic.' "2_2": 'You will see a count of new replies because you are tracking this topic.' - "2": 'You will see a count of new replies because you read this topic.' + "2": 'You will see a count of new replies because you read this topic.' "1_2": 'You will be notified if someone mentions your @name or replies to you.' "1": 'You will be notified if someone mentions your @name or replies to you.' "0_7": 'You are ignoring all notifications in this category.' @@ -2859,8 +2859,8 @@ en: total: "All time total" no_data: "No data to display." trending_search: - more: 'Search logs' - disabled: 'Trending search report is disabled. Enable log search queries to collect data.' + more: 'Search logs' + disabled: 'Trending search report is disabled. Enable log search queries to collect data.' commits: latest_changes: "Latest changes: please update often!" diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 49ece52d83..d4c3417504 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -182,7 +182,7 @@ en:

If you remember your password you can Login.

Otherwise please Reset Password.

- user_exists: "There's no need to invite %{email}, they already have an account!" + user_exists: "There's no need to invite %{email}, they already have an account!" bulk_invite: file_should_be_csv: "The uploaded file should be of csv format." @@ -357,7 +357,7 @@ en: - Include commonly used words in your topic so others can *find* it. To group your topic with related topics, select a category. - For more, [see our community guidelines](/guidelines). This panel will only appear for your first %{education_posts_text}. + For more, [see our community guidelines](%{base_path}/guidelines). This panel will only appear for your first %{education_posts_text}. 'new-reply': | Welcome to %{site_name} — **thanks for contributing!** @@ -368,7 +368,7 @@ en: - Constructive criticism is welcome, but criticize *ideas*, not people. - For more, [see our community guidelines](/guidelines). This panel will only appear for your first %{education_posts_text}. + For more, [see our community guidelines](%{base_path}/guidelines). This panel will only appear for your first %{education_posts_text}. avatar: | ### How about a picture for your account? @@ -402,7 +402,7 @@ en: Have you considered replying to *other* people in the discussion, too? A great discussion involves many voices and perspectives. - If you’d like to continue your conversation with this particular user at length, [send them a personal message](/u/%{reply_username}). + If you’d like to continue your conversation with this particular user at length, [send them a personal message](%{base_path}/u/%{reply_username}). too_many_replies: | ### You have reached the reply limit for this topic @@ -498,7 +498,7 @@ en: staff_category_description: "Private category for staff discussions. Topics are only visible to admins and moderators." assets_topic_title: "Assets for the site design" - assets_topic_body: "This topic, visible only to staff, is for storing images and files used in the site design. Don't delete it!\n\n\nHere's how:\n\n\n1. Reply to this topic.\n2. Upload all the images you wish to use for logos, favicons, and so forth here. (Use the upload toolbar icon in the post editor, or drag-and-drop or paste images.)\n3. Submit your reply to post it.\n4. Right click the images in your new post to get the path to the uploaded images, or click the edit icon to edit your post and retrieve the path to the images. Copy the image paths.\n5. Paste those image paths into [basic settings](/admin/site_settings/category/required).\n\n\nIf you need to enable different file type uploads, edit `authorized_extensions` in the [file settings](/admin/site_settings/category/files)." + assets_topic_body: "This topic, visible only to staff, is for storing images and files used in the site design. Don't delete it!\n\n\nHere's how:\n\n\n1. Reply to this topic.\n2. Upload all the images you wish to use for logos, favicons, and so forth here. (Use the upload toolbar icon in the post editor, or drag-and-drop or paste images.)\n3. Submit your reply to post it.\n4. Right click the images in your new post to get the path to the uploaded images, or click the edit icon to edit your post and retrieve the path to the images. Copy the image paths.\n5. Paste those image paths into [basic settings](%{base_path}/admin/site_settings/category/required).\n\n\nIf you need to enable different file type uploads, edit `authorized_extensions` in the [file settings](%{base_path}/admin/site_settings/category/files)." discourse_welcome_topic: title: "Welcome to Discourse" @@ -513,7 +513,7 @@ en: - Why should they come here? - Where can they read more (links, resources, etc)? - + You may want to close this topic via the admin :wrench: (at the upper right and bottom), so that replies don't pile up on an announcement. @@ -534,7 +534,7 @@ en: * Access a private Lounge category only visible to users at trust level 3 and higher * Hide spam with a single flag - Here's the [current list of fellow regulars](/badges/3/regular). Be sure to say hi. + Here's the [current list of fellow regulars](%{base_path}/badges/3/regular). Be sure to say hi. Thanks for being an important part of this community! @@ -768,8 +768,8 @@ en: email_body: "%{link}\n\n%{message}" inappropriate: title: 'Inappropriate' - description: 'This post contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' - short_description: 'A violation of our community guidelines' + description: 'This post contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' + short_description: 'A violation of our community guidelines' long_form: 'flagged this as inappropriate' notify_user: title: 'Send @{{username}} a message' @@ -820,12 +820,12 @@ en: short_description: 'This is an advertisement' inappropriate: title: 'Inappropriate' - description: 'This topic contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' + description: 'This topic contains content that a reasonable person would consider offensive, abusive, or a violation of our community guidelines.' long_form: 'flagged this as inappropriate' - short_description: 'A violation of our community guidelines' + short_description: 'A violation of our community guidelines' notify_moderators: title: "Something Else" - description: 'This topic requires general staff attention based on the guidelines, TOS, or for another reason not listed above.' + description: 'This topic requires general staff attention based on the guidelines, TOS, or for another reason not listed above.' long_form: 'flagged this for moderator attention' short_description: 'Requires staff attention for another reason' email_title: 'The topic "%{title}" requires moderator attention' @@ -1133,23 +1133,23 @@ en: sidekiq_warning: 'Sidekiq is not running. Many tasks, like sending emails, are executed asynchronously by sidekiq. Please ensure at least one sidekiq process is running. Learn about Sidekiq here.' queue_size_warning: 'The number of queued jobs is %{queue_size}, which is high. This could indicate a problem with the Sidekiq process(es), or you may need to add more Sidekiq workers.' memory_warning: 'Your server is running with less than 1 GB of total memory. At least 1 GB of memory is recommended.' - google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google OAuth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' - s3_config_warning: 'The server is configured to upload files to s3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key, s3_use_iam_profile, or s3_upload_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' - s3_backup_config_warning: 'The server is configured to upload backups to s3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key, s3_use_iam_profile, or s3_backup_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' + google_oauth2_config_warning: 'The server is configured to allow signup and log in with Google OAuth2 (enable_google_oauth2_logins), but the client id and client secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' + facebook_config_warning: 'The server is configured to allow signup and log in with Facebook (enable_facebook_logins), but the app id and app secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' + twitter_config_warning: 'The server is configured to allow signup and log in with Twitter (enable_twitter_logins), but the key and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' + github_config_warning: 'The server is configured to allow signup and log in with GitHub (enable_github_logins), but the client id and secret values are not set. Go to the Site Settings and update the settings. See this guide to learn more.' + s3_config_warning: 'The server is configured to upload files to S3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key, s3_use_iam_profile, or s3_upload_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' + s3_backup_config_warning: 'The server is configured to upload backups to S3, but at least one the following setting is not set: s3_access_key_id, s3_secret_access_key, s3_use_iam_profile, or s3_backup_bucket. Go to the Site Settings and update the settings. See "How to set up image uploads to S3?" to learn more.' image_magick_warning: 'The server is configured to create thumbnails of large images, but ImageMagick is not installed. Install ImageMagick using your favorite package manager or download the latest release.' - failing_emails_warning: 'There are %{num_failed_jobs} email jobs that failed. Check your app.yml and ensure that the mail server settings are correct. See the failed jobs in Sidekiq.' + failing_emails_warning: 'There are %{num_failed_jobs} email jobs that failed. Check your app.yml and ensure that the mail server settings are correct. See the failed jobs in Sidekiq.' subfolder_ends_in_slash: "Your subfolder setup is incorrect; the DISCOURSE_RELATIVE_URL_ROOT ends in a slash." email_polling_errored_recently: - one: "Email polling has generated an error in the past 24 hours. Look at the logs for more details." - other: "Email polling has generated %{count} errors in the past 24 hours. Look at the logs for more details." + one: "Email polling has generated an error in the past 24 hours. Look at the logs for more details." + other: "Email polling has generated %{count} errors in the past 24 hours. Look at the logs for more details." missing_mailgun_api_key: "The server is configured to send emails via Mailgun but you haven't provided an API key used to verify the webhook messages." - bad_favicon_url: "The favicon is failing to load. Check your favicon_url setting in Site Settings." - poll_pop3_timeout: "Connection to the POP3 server is timing out. Incoming email could not be retrieved. Please check your POP3 settings and service provider." - poll_pop3_auth_error: "Connection to the POP3 server is failing with an authentication error. Please check your POP3 settings." - force_https_warning: "Your website is using SSL. But `force_https` is not yet enabled in your site settings." + bad_favicon_url: "The favicon is failing to load. Check your favicon_url setting in Site Settings." + poll_pop3_timeout: "Connection to the POP3 server is timing out. Incoming email could not be retrieved. Please check your POP3 settings and service provider." + poll_pop3_auth_error: "Connection to the POP3 server is failing with an authentication error. Please check your POP3 settings." + force_https_warning: "Your website is using SSL. But `force_https` is not yet enabled in your site settings." out_of_date_themes: "Updates are available for the following themes:" unreachable_themes: "We were unable to check for updates on the following themes:" @@ -1184,8 +1184,8 @@ en: educate_until_posts: "When the user starts typing their first (n) new posts, show the pop-up new user education panel in the composer." title: "The name of this site, as used in the title tag." site_description: "Describe this site in one sentence, as used in the meta description tag." - contact_email: "Email address of key contact responsible for this site. Used for critical notifications, as well as on the /about contact form for urgent matters." - contact_url: "Contact URL for this site. Used on the /about contact form for urgent matters." + contact_email: "Email address of key contact responsible for this site. Used for critical notifications, as well as on the /about contact form for urgent matters." + contact_url: "Contact URL for this site. Used on the /about contact form for urgent matters." crawl_images: "Retrieve images from remote URLs to insert the correct width and height dimensions." download_remote_images_to_local: "Convert remote images to local images by downloading them; this prevents broken images." download_remote_images_threshold: "Minimum disk space necessary to download remote images locally (in percent)" @@ -1215,12 +1215,12 @@ en: enable_inline_onebox_on_all_domains: "Ignore inline_onebox_domain_whitelist site setting and allow inline onebox on all domains." max_oneboxes_per_post: "Maximum number of oneboxes in a post." - logo_url: "The logo image at the top left of your site, should be a wide rectangle shape. If left blank site title text will be shown. Use the wizard to update." + logo_url: "The logo image at the top left of your site, should be a wide rectangle shape. If left blank site title text will be shown. Use the wizard to update." digest_logo_url: "The alternate logo image used at the top of your site's email summary. Should be a wide rectangle shape. Should not be an SVG image. If left blank `logo_url` will be used." - logo_small_url: "The small logo image at the top left of your site, should be a square shape, seen when scrolling down. If left blank a home glyph will be shown. Use the wizard to update." - favicon_url: "A favicon for your site, see https://en.wikipedia.org/wiki/Favicon. To work correctly over a CDN it must be a png. Use the wizard to update." + logo_small_url: "The small logo image at the top left of your site, should be a square shape, seen when scrolling down. If left blank a home glyph will be shown. Use the wizard to update." + favicon_url: "A favicon for your site, see https://en.wikipedia.org/wiki/Favicon. To work correctly over a CDN it must be a png. Use the wizard to update." mobile_logo_url: "Custom logo url used on mobile version of your site. If left blank, `logo_url` will be used. eg: https://example.com/uploads/default/logo.png" - large_icon_url: "Image used as logo/splash image on Android. Recommended size is 512px by 512px. Use the wizard to update." + large_icon_url: "Image used as logo/splash image on Android. Recommended size is 512px by 512px. Use the wizard to update." apple_touch_icon_url: "Icon used for Apple touch devices. Recommended size is 144px by 144px." notification_email: "The from: email address used when sending all essential system emails. The domain specified here must have SPF, DKIM and reverse PTR records set correctly for email to arrive." @@ -1316,7 +1316,7 @@ en: email_domains_whitelist: "A pipe-delimited list of email domains that users MUST register accounts with. WARNING: Users with email domains other than those listed will not be allowed!" hide_email_address_taken: "Don't inform users that an account exists with a given email address during signup and from the forgot password form." log_out_strict: "When logging out, log out ALL sessions for the user on all devices" - version_checks: "Ping the Discourse Hub for version updates and show new version messages on the /admin dashboard" + version_checks: "Ping the Discourse Hub for version updates and show new version messages on the /admin dashboard" new_version_emails: "Send an email to the contact_email address when a new version of Discourse is available." invite_expiry_days: "How long user invitation keys are valid, in days" @@ -1336,7 +1336,7 @@ en: block_common_passwords: "Don't allow passwords that are in the 10,000 most common passwords." enable_sso: "Enable single sign on via an external site (WARNING: USERS' EMAIL ADDRESSES *MUST* BE VALIDATED BY THE EXTERNAL SITE!)" - verbose_sso_logging: "Log verbose SSO related diagnostics to /logs" + verbose_sso_logging: "Log verbose SSO related diagnostics to /logs" enable_sso_provider: "Implement Discourse SSO provider protocol at the /session/sso_provider endpoint, requires sso_provider_secrets to be set" sso_url: "URL of single sign on endpoint (must include http:// or https://)" sso_secret: "Secret string used to cryptographically authenticate SSO information, be sure it is 10 characters or longer" @@ -1606,8 +1606,8 @@ en: min_flags_staff_visibility: "The minimum amount of flags on a post must have before staff can see it in the admin section" reply_by_email_enabled: "Enable replying to topics via email." - reply_by_email_address: "Template for reply by email incoming email address, for example: %{reply_key}@reply.example.com or replies+%{reply_key}@example.com" - alternative_reply_by_email_addresses: "List of alternative templates for reply by email incoming email addresses. Example: %{reply_key}@reply.example.com|replies+%{reply_key}@example.com" + reply_by_email_address: "Template for reply by email incoming email address, for example: %%{reply_key}@reply.example.com or replies+%%{reply_key}@example.com" + alternative_reply_by_email_addresses: "List of alternative templates for reply by email incoming email addresses. Example: %%{reply_key}@reply.example.com|replies+%%{reply_key}@example.com" incoming_email_prefer_html: "Use HTML instead of text for incoming email." disable_emails: "Prevent Discourse from sending any kind of emails. Select 'yes' to disable emails for all users. Select 'non-staff' to disable emails for non-staff users only." @@ -1652,7 +1652,7 @@ en: pop3_polling_username: "The username for the POP3 account to poll for email." pop3_polling_password: "The password for the POP3 account to poll for email." pop3_polling_delete_from_server: "Delete emails from server. NOTE: If you disable this you should manually clean your mail inbox" - log_mail_processing_failures: "Log all email processing failures to /logs" + log_mail_processing_failures: "Log all email processing failures to /logs" email_in: "Allow users to post new topics via email (requires manual or pop3 polling). Configure the addresses in the \"Settings\" tab of each category." email_in_min_trust: "The minimum trust level a user needs to have to be allowed to post new topics via email." email_in_spam_header: "The email header to detect spam." @@ -1692,7 +1692,7 @@ en: staff_user_custom_fields: "A whitelist of custom fields for a user that can be shown to staff." enable_user_directory: "Provide a directory of users for browsing" enable_group_directory: "Provide a directory of groups for browsing" - group_in_subject: "Set %{optional_pm} in email subject to name of first group in PM, see: Customize subject format for standard emails" + group_in_subject: "Set %%{optional_pm} in email subject to name of first group in PM, see: Customize subject format for standard emails" allow_anonymous_posting: "Allow users to switch to anonymous mode" anonymous_posting_min_trust_level: "Minimum trust level required to enable anonymous posting" anonymous_account_duration_minutes: "To protect anonymity create a new anonymous account every N minutes for each user. Example: if set to 600, as soon as 600 minutes elapse from last post AND user switches to anon, a new anonymous account is created." @@ -1835,7 +1835,7 @@ en: show_filter_by_tag: "Show a dropdown to filter a topic list by tag." max_tags_in_filter_list: "Maximum number of tags to show in the filter dropdown. The most used tags will be shown." tags_sort_alphabetically: "Show tags in alphabetical order. Default is to show in order of popularity." - tags_listed_by_group: "List tags by tag group on the Tags page." + tags_listed_by_group: "List tags by tag group on the Tags page." tag_style: "Visual style for tag badges." allow_staff_to_tag_pms: "Allow staff members to tag any personal message" min_trust_level_to_tag_topics: "Minimum trust level required to tag topics" @@ -1865,8 +1865,8 @@ en: invalid_string_min_max: "Must be between %{min} and %{max} characters." invalid_string_min: "Must be at least %{min} characters." invalid_string_max: "Must be no more than %{max} characters." - invalid_reply_by_email_address: "Value must contain '%{reply_key}' and be different from the notification email." - invalid_alternative_reply_by_email_addresses: "All values must contain '%{reply_key}' and be different from the notification email." + invalid_reply_by_email_address: "Value must contain '%%{reply_key}' and be different from the notification email." + invalid_alternative_reply_by_email_addresses: "All values must contain '%%{reply_key}' and be different from the notification email." pop3_polling_host_is_empty: "You must set a 'pop3 polling host' before enabling POP3 polling." pop3_polling_username_is_empty: "You must set a 'pop3 polling username' before enabling POP3 polling." pop3_polling_password_is_empty: "You must set a 'pop3 polling password' before enabling POP3 polling." @@ -2069,8 +2069,8 @@ en: flags_reminder: flags_were_submitted: - one: "Flags were submitted over 1 hour ago. [Please review them](/admin/flags)." - other: "Flags were submitted over %{count} hours ago. [Please review them](/admin/flags)." + one: "Flags were submitted over 1 hour ago. [Please review them](%{base_path}/admin/flags)." + other: "Flags were submitted over %{count} hours ago. [Please review them](%{base_path}/admin/flags)." subject_template: one: "1 flag waiting to be handled" other: "%{count} flags waiting to be handled" @@ -2271,7 +2271,7 @@ en: flag_reasons: off_topic: "Your post was flagged as **off-topic**: the community feels it is not a good fit for the topic, as currently defined by the title and the first post." - inappropriate: "Your post was flagged as **inappropriate**: the community feels it is offensive, abusive, or a violation of [our community guidelines](/guidelines)." + inappropriate: "Your post was flagged as **inappropriate**: the community feels it is offensive, abusive, or a violation of [our community guidelines](%{base_path}/guidelines)." spam: "Your post was flagged as **spam**: the community feels it is an advertisement, something that is overly promotional in nature instead of being useful or relevant to the topic as expected." notify_moderators: "Your post was flagged **for moderator attention**: the community feels something about the post requires manual intervention by a staff member." @@ -3276,7 +3276,7 @@ en: terms_of_service: title: "Terms of Service" - signup_form_message: 'I have read and accept the Terms of Service.' + signup_form_message: 'I have read and accept the Terms of Service.' deleted: 'deleted' @@ -3303,8 +3303,8 @@ en: missing: "Sorry, we can't find any avatar associated with that email address. Can you try uploading it again?" flag_reason: - sockpuppet: "A new user created a topic, and another new user at the same IP address (%{ip_address}) replied. See the `flag_sockpuppets` site setting." - spam_hosts: "This new user tried to create multiple posts with links to the same domain (%{domain}). See the `newuser_spam_host_threshold` site setting." + sockpuppet: "A new user created a topic, and another new user at the same IP address (%{ip_address}) replied. See the `flag_sockpuppets` site setting." + spam_hosts: "This new user tried to create multiple posts with links to the same domain (%{domain}). See the `newuser_spam_host_threshold` site setting." skipped_email_log: exceeded_emails_limit: "Exceeded max_emails_per_day_per_user" @@ -3453,19 +3453,19 @@ en: ## [Powered by You](#power) - This site is operated by your [friendly local staff](/about) and *you*, the community. If you have any further questions about how things should work here, open a new topic in the [site feedback category](/c/site-feedback) and let's discuss! If there's a critical or urgent issue that can't be handled by a meta topic or flag, contact us via the [staff page](/about). + This site is operated by your [friendly local staff](%{base_path}/about) and *you*, the community. If you have any further questions about how things should work here, open a new topic in the [site feedback category](%{base_path}/c/site-feedback) and let's discuss! If there's a critical or urgent issue that can't be handled by a meta topic or flag, contact us via the [staff page](%{base_path}/about). ## [Terms of Service](#tos) - Yes, legalese is boring, but we must protect ourselves – and by extension, you and your data – against unfriendly folks. We have a [Terms of Service](/tos) describing your (and our) behavior and rights related to content, privacy, and laws. To use this service, you must agree to abide by our [TOS](/tos). + Yes, legalese is boring, but we must protect ourselves – and by extension, you and your data – against unfriendly folks. We have a [Terms of Service](%{base_path}/tos) describing your (and our) behavior and rights related to content, privacy, and laws. To use this service, you must agree to abide by our [TOS](%{base_path}/tos). tos_topic: title: "Terms of Service" body: | - The following terms and conditions govern all use of the %{company_domain} website and all content, services and products available at or through the website, including, but not limited to, %{company_domain} Forum Software, %{company_domain} Support Forums and the %{company_domain} Hosting service ("Hosting"), (taken together, the Website). The Website is owned and operated by %{company_full_name} ("%{company_name}"). The Website is offered subject to your acceptance without modification of all of the terms and conditions contained herein and all other operating rules, policies (including, without limitation, %{company_domain}’s [Privacy Policy](/privacy) and [Community Guidelines](/faq)) and procedures that may be published from time to time on this Site by %{company_name} (collectively, the "Agreement"). + The following terms and conditions govern all use of the %{company_domain} website and all content, services and products available at or through the website, including, but not limited to, %{company_domain} Forum Software, %{company_domain} Support Forums and the %{company_domain} Hosting service ("Hosting"), (taken together, the Website). The Website is owned and operated by %{company_full_name} ("%{company_name}"). The Website is offered subject to your acceptance without modification of all of the terms and conditions contained herein and all other operating rules, policies (including, without limitation, %{company_domain}’s [Privacy Policy](%{base_path}/privacy) and [Community Guidelines](%{base_path}/faq)) and procedures that may be published from time to time on this Site by %{company_name} (collectively, the "Agreement"). Please read this Agreement carefully before accessing or using the Website. By accessing or using any part of the web site, you agree to become bound by the terms and conditions of this agreement. If you do not agree to all the terms and conditions of this agreement, then you may not access the Website or use any services. If these terms and conditions are considered an offer by %{company_name}, acceptance is expressly limited to these terms. The Website is available only to individuals who are at least 13 years old. @@ -3584,7 +3584,7 @@ en: ## [15. General Representation and Warranty](#15) - You represent and warrant that (i) your use of the Website will be in strict accordance with the %{company_name} [Privacy Policy](/privacy), [Community Guidelines](/guidelines), with this Agreement and with all applicable laws and regulations (including without limitation any local laws or regulations in your country, state, city, or other governmental area, regarding online conduct and acceptable content, and including all applicable laws regarding the transmission of technical data exported from the country in which this website resides or the country in which you reside) and (ii) your use of the Website will not infringe or misappropriate the intellectual property rights of any third party. + You represent and warrant that (i) your use of the Website will be in strict accordance with the %{company_name} [Privacy Policy](%{base_path}/privacy), [Community Guidelines](%{base_path}/guidelines), with this Agreement and with all applicable laws and regulations (including without limitation any local laws or regulations in your country, state, city, or other governmental area, regarding online conduct and acceptable content, and including all applicable laws regarding the transmission of technical data exported from the country in which this website resides or the country in which you reside) and (ii) your use of the Website will not infringe or misappropriate the intellectual property rights of any third party. @@ -4029,18 +4029,18 @@ en: contact_email: label: "Mail" placeholder: "name@example.com" - description: "Email address for the person or group responsible for this community. Used for critical notifications such as unhandled flags, security updates, and on your about page for urgent community contact." + description: "Email address for the person or group responsible for this community. Used for critical notifications such as unhandled flags, security updates, and on your about page for urgent community contact." contact_url: label: "Web Page" placeholder: "https://www.example.com/contact-us" - description: "General contact web page for you or your organization. Will be displayed on your about page." + description: "General contact web page for you or your organization. Will be displayed on your about page." site_contact: label: "Automated Messages" description: "All automated Discourse personal messages will be sent from this user, such as flag warnings and backup completion notices." corporate: title: "Organization" - description: "These names will be entered in your Privacy Policy and Terms of Service, which are topics you can edit in the Staff category. If you don’t have a company, feel free to skip this step for now." + description: "These names will be entered in your Privacy Policy and Terms of Service, which are topics you can edit in the Staff category. If you don’t have a company, feel free to skip this step for now." fields: company_short_name: @@ -4117,7 +4117,7 @@ en: finished: title: "Your Discourse is Ready!" description: | -

If you ever feel like changing these settings, re-run this wizard any time, or visit your admin section; find it next to the wrench icon in the site menu.

+

If you ever feel like changing these settings, re-run this wizard any time, or visit your admin section; find it next to the wrench icon in the site menu.

Have fun, and good luck building your new community!

search_logs: diff --git a/db/fixtures/990_topics.rb b/db/fixtures/990_topics.rb index 45bb8d4299..308b030785 100644 --- a/db/fixtures/990_topics.rb +++ b/db/fixtures/990_topics.rb @@ -28,9 +28,10 @@ unless Rails.env.test? create_static_page_topic('tos_topic_id', 'tos_topic.title', "tos_topic.body", nil, staff, "terms of service", company_domain: "company_domain", company_full_name: "company_full_name", - company_name: "company_short_name") + company_name: "company_short_name", + base_path: Discourse.base_path) - create_static_page_topic('guidelines_topic_id', 'guidelines_topic.title', "guidelines_topic.body", nil, staff, "guidelines") + create_static_page_topic('guidelines_topic_id', 'guidelines_topic.title', "guidelines_topic.body", nil, staff, "guidelines", base_path: Discourse.base_path) create_static_page_topic('privacy_topic_id', 'privacy_topic.title', "privacy_topic.body", nil, staff, "privacy policy") end @@ -38,15 +39,15 @@ end if seed_welcome_topics puts "Seeding welcome topics" - PostCreator.create(Discourse.system_user, raw: I18n.t('assets_topic_body'), title: I18n.t('assets_topic_title'), skip_validations: true, category: staff ? staff.name : nil) + PostCreator.create(Discourse.system_user, raw: I18n.t('assets_topic_body', base_path: Discourse.base_path), title: I18n.t('assets_topic_title'), skip_validations: true, category: staff ? staff.name : nil) - post = PostCreator.create(Discourse.system_user, raw: I18n.t('discourse_welcome_topic.body'), title: I18n.t('discourse_welcome_topic.title'), skip_validations: true) + post = PostCreator.create(Discourse.system_user, raw: I18n.t('discourse_welcome_topic.body', base_path: Discourse.base_path), title: I18n.t('discourse_welcome_topic.title'), skip_validations: true) post.topic.update_pinned(true, true) TopicCustomField.create(topic_id: post.topic.id, name: "is_welcome_topic", value: "true") lounge = Category.find_by(id: SiteSetting.lounge_category_id) if lounge - post = PostCreator.create(Discourse.system_user, raw: I18n.t('lounge_welcome.body'), title: I18n.t('lounge_welcome.title'), skip_validations: true, category: lounge.name) + post = PostCreator.create(Discourse.system_user, raw: I18n.t('lounge_welcome.body', base_path: Discourse.base_path), title: I18n.t('lounge_welcome.title'), skip_validations: true, category: lounge.name) post.topic.update_pinned(true) end diff --git a/db/migrate/20140929204155_migrate_tos_setting.rb b/db/migrate/20140929204155_migrate_tos_setting.rb index 6f2e91a534..623423ed4e 100644 --- a/db/migrate/20140929204155_migrate_tos_setting.rb +++ b/db/migrate/20140929204155_migrate_tos_setting.rb @@ -5,7 +5,7 @@ class MigrateTosSetting < ActiveRecord::Migration[4.2] label = nil I18n.overrides_disabled do - label = I18n.t("terms_of_service.signup_form_message") + label = I18n.t("terms_of_service.signup_form_message", base_path: "") end res = execute("SELECT value FROM site_texts WHERE text_type = 'tos_signup_form_message'") diff --git a/db/migrate/20141014191645_fix_tos_name.rb b/db/migrate/20141014191645_fix_tos_name.rb index 16976a944d..e71be1d465 100644 --- a/db/migrate/20141014191645_fix_tos_name.rb +++ b/db/migrate/20141014191645_fix_tos_name.rb @@ -1,7 +1,7 @@ class FixTosName < ActiveRecord::Migration[4.2] def up I18n.overrides_disabled do - execute DB.sql_fragment('UPDATE user_fields SET name = ? WHERE name = ?', I18n.t('terms_of_service.title'), I18n.t("terms_of_service.signup_form_message")) + execute DB.sql_fragment('UPDATE user_fields SET name = ? WHERE name = ?', I18n.t('terms_of_service.title'), I18n.t("terms_of_service.signup_form_message", base_path: "")) end end diff --git a/lib/composer_messages_finder.rb b/lib/composer_messages_finder.rb index 3a8c9f2d62..e80c27bc6a 100644 --- a/lib/composer_messages_finder.rb +++ b/lib/composer_messages_finder.rb @@ -34,12 +34,18 @@ class ComposerMessagesFinder end if count < SiteSetting.educate_until_posts - education_posts_text = I18n.t('education.until_posts', count: SiteSetting.educate_until_posts) return { id: 'education', templateName: 'education', wait_for_typing: true, - body: PrettyText.cook(I18n.t(education_key, education_posts_text: education_posts_text, site_name: SiteSetting.title)) + body: PrettyText.cook( + I18n.t( + education_key, + education_posts_text: I18n.t('education.until_posts', count: SiteSetting.educate_until_posts), + site_name: SiteSetting.title, + base_path: Discourse.base_path + ) + ) } end @@ -173,7 +179,8 @@ class ComposerMessagesFinder I18n.t( 'education.get_a_room', count: SiteSetting.get_a_room_threshold, - reply_username: reply_username + reply_username: reply_username, + base_path: Discourse.base_path ) ) } @@ -191,7 +198,12 @@ class ComposerMessagesFinder templateName: 'education', wait_for_typing: false, extraClass: 'education-message', - body: PrettyText.cook(I18n.t('education.reviving_old_topic', time_ago: FreedomPatches::Rails4.time_ago_in_words(@topic.last_posted_at, false, scope: :'datetime.distance_in_words_verbose'))) + body: PrettyText.cook( + I18n.t( + 'education.reviving_old_topic', + time_ago: FreedomPatches::Rails4.time_ago_in_words(@topic.last_posted_at, false, scope: :'datetime.distance_in_words_verbose') + ) + ) } end diff --git a/lib/post_destroyer.rb b/lib/post_destroyer.rb index 87ded044d6..617cc7749a 100644 --- a/lib/post_destroyer.rb +++ b/lib/post_destroyer.rb @@ -227,7 +227,11 @@ class PostDestroyer message_type: :flags_agreed_and_post_deleted, message_options: { url: @post.url, - flag_reason: I18n.t("flag_reasons.#{@post.active_flags.last.post_action_type.name_key}", locale: SiteSetting.default_locale) + flag_reason: I18n.t( + "flag_reasons.#{@post.active_flags.last.post_action_type.name_key}", + locale: SiteSetting.default_locale, + base_path: Discourse.base_path + ) } ) end diff --git a/lib/site_setting_extension.rb b/lib/site_setting_extension.rb index 9122da94d9..b556584a0d 100644 --- a/lib/site_setting_extension.rb +++ b/lib/site_setting_extension.rb @@ -229,7 +229,7 @@ module SiteSettingExtension end def description(setting) - I18n.t("site_settings.#{setting}") + I18n.t("site_settings.#{setting}", base_path: Discourse.base_path) end def placeholder(setting) diff --git a/lib/tasks/topics.rake b/lib/tasks/topics.rake index e9720e76f6..b7f6d63314 100644 --- a/lib/tasks/topics.rake +++ b/lib/tasks/topics.rake @@ -91,9 +91,11 @@ task "topics:update_static", [:locale] => [:environment] do |_, args| update_static_page_topic(locale, "tos_topic_id", "tos_topic.title", "tos_topic.body", company_domain: SiteSetting.company_domain.presence || "company_domain", company_full_name: SiteSetting.company_full_name.presence || "company_full_name", - company_name: SiteSetting.company_short_name.presence || "company_short_name") + company_name: SiteSetting.company_short_name.presence || "company_short_name", + base_path: Discourse.base_path) - update_static_page_topic(locale, "guidelines_topic_id", "guidelines_topic.title", "guidelines_topic.body") + update_static_page_topic(locale, "guidelines_topic_id", "guidelines_topic.title", "guidelines_topic.body", + base_path: Discourse.base_path) update_static_page_topic(locale, "privacy_topic_id", "privacy_topic.title", "privacy_topic.body") end diff --git a/plugins/discourse-narrative-bot/config/locales/server.en.yml b/plugins/discourse-narrative-bot/config/locales/server.en.yml index 70557957dd..a61f030196 100644 --- a/plugins/discourse-narrative-bot/config/locales/server.en.yml +++ b/plugins/discourse-narrative-bot/config/locales/server.en.yml @@ -139,7 +139,7 @@ en: second_response: |- Aw, sorry. I’m still not getting it. :anguished: - I’m just a bot, but if you’d like to reach a real person, see [our contact page](/about). + I’m just a bot, but if you’d like to reach a real person, see [our contact page](%{base_path}/about). In the meantime, I’ll stay out of your way. diff --git a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/track_selector.rb b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/track_selector.rb index 9d4c68fe1d..74bd2a455d 100644 --- a/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/track_selector.rb +++ b/plugins/discourse-narrative-bot/lib/discourse_narrative_bot/track_selector.rb @@ -201,7 +201,8 @@ module DiscourseNarrativeBot reply_to(@post, raw) when 1 reply_to(@post, I18n.t(self.class.i18n_key('do_not_understand.second_response'), - reset_trigger: self.class.reset_trigger + base_path: Discourse.base_path, + reset_trigger: self.class.reset_trigger )) else # Stay out of the user's way diff --git a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb index 7f0effc906..0e6cb7a43f 100644 --- a/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb +++ b/plugins/discourse-narrative-bot/spec/discourse_narrative_bot/track_selector_spec.rb @@ -258,6 +258,7 @@ describe DiscourseNarrativeBot::TrackSelector do expect(new_post.raw).to eq(I18n.t( 'discourse_narrative_bot.track_selector.do_not_understand.second_response', + base_path: Discourse.base_path, reset_trigger: "#{described_class.reset_trigger} #{DiscourseNarrativeBot::NewUserNarrative.reset_trigger}", )) diff --git a/spec/components/site_setting_extension_spec.rb b/spec/components/site_setting_extension_spec.rb index 3f2b862c4a..46e9a71c23 100644 --- a/spec/components/site_setting_extension_spec.rb +++ b/spec/components/site_setting_extension_spec.rb @@ -155,8 +155,11 @@ describe SiteSettingExtension do end it "should have the correct desc" do - I18n.expects(:t).with("site_settings.test_setting").returns("test description") - expect(settings.description(:test_setting)).to eq("test description") + I18n.backend.store_translations(:en, site_settings: { test_setting: "test description /admin" }) + expect(settings.description(:test_setting)).to eq("test description /admin") + + Discourse.stubs(:base_path).returns("/forum") + expect(settings.description(:test_setting)).to eq("test description /admin") end it "should have the correct default" do diff --git a/spec/integrity/i18n_spec.rb b/spec/integrity/i18n_spec.rb index b564c27d01..6f0e11a8c0 100644 --- a/spec/integrity/i18n_spec.rb +++ b/spec/integrity/i18n_spec.rb @@ -36,6 +36,18 @@ def is_yaml_compatible?(english, translated) true end +def each_translation(hash, parent_key = '', &block) + hash.each do |key, value| + current_key = parent_key.blank? ? key : "#{parent_key}.#{key}" + + if Hash === value + each_translation(value, current_key, &block) + else + yield(current_key, value.to_s) + end + end +end + describe "i18n integrity checks" do it 'has an i18n key for each Trust Levels' do @@ -97,6 +109,29 @@ describe "i18n integrity checks" do expect(hash.keys).to contain_exactly("one", "other") end end + + context "valid translations" do + invalid_relative_links = {} + invalid_relative_image_sources = {} + + each_translation(english_yaml) do |key, value| + if value.match?(/href\s*=\s*["']\/[^\/]|\]\(\/[^\/]/i) + invalid_relative_links[key] = value + elsif value.match?(/src\s*=\s*["']\/[^\/]/i) + invalid_relative_image_sources[key] = value + end + end + + it "uses %{base_url} or %{base_path} for relative links" do + keys = invalid_relative_links.keys.join("\n") + expect(invalid_relative_links).to be_empty, "The following keys have relative links, but do not start with %{base_url} or %{base_path}:\n\n#{keys}" + end + + it "uses %{base_url} or %{base_path} for relative image src" do + keys = invalid_relative_image_sources.keys.join("\n") + expect(invalid_relative_image_sources).to be_empty, "The following keys have relative image sources, but do not start with %{base_url} or %{base_path}:\n\n#{keys}" + end + end end Dir[english_path.sub(".en.yml", ".*.yml")].each do |path| diff --git a/spec/jobs/poll_mailbox_spec.rb b/spec/jobs/poll_mailbox_spec.rb index 95824bcd5c..d9c7d485f4 100644 --- a/spec/jobs/poll_mailbox_spec.rb +++ b/spec/jobs/poll_mailbox_spec.rb @@ -43,7 +43,7 @@ describe Jobs::PollMailbox do i18n_key = 'dashboard.poll_pop3_auth_error' expect(AdminDashboardData.problem_message_check(i18n_key)) - .to eq(I18n.t(i18n_key)) + .to eq(I18n.t(i18n_key, base_path: Discourse.base_path)) end it "logs an error on pop connection timeout error" do @@ -54,7 +54,7 @@ describe Jobs::PollMailbox do i18n_key = 'dashboard.poll_pop3_timeout' expect(AdminDashboardData.problem_message_check(i18n_key)) - .to eq(I18n.t(i18n_key)) + .to eq(I18n.t(i18n_key, base_path: Discourse.base_path)) end end diff --git a/spec/models/admin_dashboard_data_spec.rb b/spec/models/admin_dashboard_data_spec.rb index 690ed831e8..9ba85feb00 100644 --- a/spec/models/admin_dashboard_data_spec.rb +++ b/spec/models/admin_dashboard_data_spec.rb @@ -306,7 +306,7 @@ describe AdminDashboardData do it 'returns nil if force_https site setting not enabled' do SiteSetting.force_https = false - expect(subject).to eq(I18n.t('dashboard.force_https_warning')) + expect(subject).to eq(I18n.t('dashboard.force_https_warning', base_path: Discourse.base_path)) end end @@ -339,12 +339,12 @@ describe AdminDashboardData do it 'returns a message if it was added' do described_class.add_problem_message(key) - expect(described_class.problem_message_check(key)).to eq(I18n.t(key)) + expect(described_class.problem_message_check(key)).to eq(I18n.t(key, base_path: Discourse.base_path)) end it 'returns a message if it was added with an expiry' do described_class.add_problem_message(key, 300) - expect(described_class.problem_message_check(key)).to eq(I18n.t(key)) + expect(described_class.problem_message_check(key)).to eq(I18n.t(key, base_path: Discourse.base_path)) end end