Encapsulate translation constants and functions inside it's own module (#5637)

It encapsulates all related code from translation into it's own module.

Required for the migration to the crystal stdlib logger: https://github.com/iv-org/invidious/pull/5426
This commit is contained in:
Fijxu 2026-04-25 16:55:55 -04:00 committed by GitHub
parent 54365c0e2a
commit bc64cd9b67
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
54 changed files with 562 additions and 558 deletions

View File

@ -24,7 +24,7 @@ def create_licence_tr(path, file_name, licence_name, licence_link, source_locati
"<tr> "<tr>
<td><a href=\\"/#{path}\\">#{file_name}</a></td> <td><a href=\\"/#{path}\\">#{file_name}</a></td>
<td><a href=\\"#{licence_link}\\">#{licence_name}</a></td> <td><a href=\\"#{licence_link}\\">#{licence_name}</a></td>
<td><a href=\\"#{source_location}\\">\#{translate(locale, "source")}</a></td> <td><a href=\\"#{source_location}\\">\#{I18n.translate(locale, "source")}</a></td>
</tr>" </tr>"
HTML HTML

View File

@ -38,7 +38,7 @@ struct ChannelVideo
json.field "authorId", self.ucid json.field "authorId", self.ucid
json.field "authorUrl", "/channel/#{self.ucid}" json.field "authorUrl", "/channel/#{self.ucid}"
json.field "published", self.published.to_unix json.field "published", self.published.to_unix
json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(self.published, locale))
json.field "viewCount", self.views json.field "viewCount", self.views
end end

View File

@ -131,7 +131,7 @@ def extract_channel_community(items, *, ucid, locale, format, thin_mode, is_sing
json.field "contentHtml", content_html json.field "contentHtml", content_html
json.field "published", published.to_unix json.field "published", published.to_unix
json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(published, locale))
json.field "likeCount", like_count json.field "likeCount", like_count
json.field "replyCount", reply_count json.field "replyCount", reply_count

View File

@ -268,7 +268,7 @@ module Invidious::Comments
end end
json.field "published", published.to_unix json.field "published", published.to_unix
json.field "publishedText", translate(locale, "`x` ago", recode_date(published, locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(published, locale))
end end
if node_replies && !response["commentRepliesContinuation"]? if node_replies && !response["commentRepliesContinuation"]?

View File

@ -28,14 +28,14 @@ module Invidious::Frontend::ChannelPage
if tab == selected_tab if tab == selected_tab
str << "\t<b>" str << "\t<b>"
str << translate(locale, "channel_tab_#{tab_name}_label") str << I18n.translate(locale, "channel_tab_#{tab_name}_label")
str << "</b>\n" str << "</b>\n"
else else
# Video tab doesn't have the last path component # Video tab doesn't have the last path component
url = tab.videos? ? base_url : "#{base_url}/#{tab_name}" url = tab.videos? ? base_url : "#{base_url}/#{tab_name}"
str << %(\t<a href=") << url << %(">) str << %(\t<a href=") << url << %(">)
str << translate(locale, "channel_tab_#{tab_name}_label") str << I18n.translate(locale, "channel_tab_#{tab_name}_label")
str << "</a>\n" str << "</a>\n"
end end

View File

@ -32,9 +32,9 @@ module Invidious::Frontend::Comments
<p> <p>
<a href="javascript:void(0)" data-onclick="toggle_parent">[ ]</a> <a href="javascript:void(0)" data-onclick="toggle_parent">[ ]</a>
<b><a href="https://www.reddit.com/user/#{child.author}">#{child.author}</a></b> <b><a href="https://www.reddit.com/user/#{child.author}">#{child.author}</a></b>
#{translate_count(locale, "comments_points_count", child.score, NumberFormatting::Separator)} #{I18n.translate_count(locale, "comments_points_count", child.score, I18n::NumberFormatting::Separator)}
<span title="#{child.created_utc.to_s("%a %B %-d %T %Y UTC")}">#{translate(locale, "`x` ago", recode_date(child.created_utc, locale))}</span> <span title="#{child.created_utc.to_s("%a %B %-d %T %Y UTC")}">#{I18n.translate(locale, "`x` ago", recode_date(child.created_utc, locale))}</span>
<a href="https://www.reddit.com#{child.permalink}" title="#{translate(locale, "permalink")}">#{translate(locale, "permalink")}</a> <a href="https://www.reddit.com#{child.permalink}" title="#{I18n.translate(locale, "permalink")}">#{I18n.translate(locale, "permalink")}</a>
</p> </p>
<div> <div>
#{body_html} #{body_html}

View File

@ -6,10 +6,10 @@ module Invidious::Frontend::Comments
root = comments["comments"].as_a root = comments["comments"].as_a
root.each do |child| root.each do |child|
if child["replies"]? if child["replies"]?
replies_count_text = translate_count(locale, replies_count_text = I18n.translate_count(locale,
"comments_view_x_replies", "comments_view_x_replies",
child["replies"]["replyCount"].as_i64 || 0, child["replies"]["replyCount"].as_i64 || 0,
NumberFormatting::Separator I18n::NumberFormatting::Separator
) )
replies_html = <<-END_HTML replies_html = <<-END_HTML
@ -25,10 +25,10 @@ module Invidious::Frontend::Comments
END_HTML END_HTML
elsif comments["authorId"]? && !comments["singlePost"]? elsif comments["authorId"]? && !comments["singlePost"]?
# for posts we should display a link to the post # for posts we should display a link to the post
replies_count_text = translate_count(locale, replies_count_text = I18n.translate_count(locale,
"comments_view_x_replies", "comments_view_x_replies",
child["replyCount"].as_i64 || 0, child["replyCount"].as_i64 || 0,
NumberFormatting::Separator I18n::NumberFormatting::Separator
) )
replies_html = <<-END_HTML replies_html = <<-END_HTML
@ -61,7 +61,7 @@ module Invidious::Frontend::Comments
sponsor_icon = String.build do |str| sponsor_icon = String.build do |str|
str << %(<img alt="" ) str << %(<img alt="" )
str << %(src="/ggpht) << URI.parse(child["sponsorIconUrl"].as_s).request_target << "\" " str << %(src="/ggpht) << URI.parse(child["sponsorIconUrl"].as_s).request_target << "\" "
str << %(title=") << translate(locale, "Channel Sponsor") << "\" " str << %(title=") << I18n.translate(locale, "Channel Sponsor") << "\" "
str << %(width="16" height="16" />) str << %(width="16" height="16" />)
end end
end end
@ -110,14 +110,14 @@ module Invidious::Frontend::Comments
when "multiImage" when "multiImage"
html << <<-END_HTML html << <<-END_HTML
<section class="carousel"> <section class="carousel">
<a class="skip-link" href="#skip-#{child["commentId"]}">#{translate(locale, "carousel_skip")}</a> <a class="skip-link" href="#skip-#{child["commentId"]}">#{I18n.translate(locale, "carousel_skip")}</a>
<div class="slides"> <div class="slides">
END_HTML END_HTML
image_array = attachment["images"].as_a image_array = attachment["images"].as_a
image_array.each_index do |i| image_array.each_index do |i|
html << <<-END_HTML html << <<-END_HTML
<div class="slides-item slide-#{i + 1}" id="#{child["commentId"]}-slide-#{i + 1}" aria-label="#{translate(locale, "carousel_slide", {"current" => (i + 1).to_s, "total" => image_array.size.to_s})}" tabindex="0"> <div class="slides-item slide-#{i + 1}" id="#{child["commentId"]}-slide-#{i + 1}" aria-label="#{I18n.translate(locale, "carousel_slide", {"current" => (i + 1).to_s, "total" => image_array.size.to_s})}" tabindex="0">
<img loading="lazy" src="/ggpht#{URI.parse(image_array[i][1]["url"].as_s).request_target}" alt="" /> <img loading="lazy" src="/ggpht#{URI.parse(image_array[i][1]["url"].as_s).request_target}" alt="" />
</div> </div>
END_HTML END_HTML
@ -129,7 +129,7 @@ module Invidious::Frontend::Comments
END_HTML END_HTML
attachment["images"].as_a.each_index do |i| attachment["images"].as_a.each_index do |i|
html << <<-END_HTML html << <<-END_HTML
<a class="slider-nav" href="##{child["commentId"]}-slide-#{i + 1}" aria-label="#{translate(locale, "carousel_go_to", (i + 1).to_s)}" tabindex="-1" aria-hidden="true">#{i + 1}</a> <a class="slider-nav" href="##{child["commentId"]}-slide-#{i + 1}" aria-label="#{I18n.translate(locale, "carousel_go_to", (i + 1).to_s)}" tabindex="-1" aria-hidden="true">#{i + 1}</a>
END_HTML END_HTML
end end
html << <<-END_HTML html << <<-END_HTML
@ -143,18 +143,18 @@ module Invidious::Frontend::Comments
html << <<-END_HTML html << <<-END_HTML
<p> <p>
<span title="#{Time.unix(child["published"].as_i64).to_s(translate(locale, "%A %B %-d, %Y"))}">#{translate(locale, "`x` ago", recode_date(Time.unix(child["published"].as_i64), locale))} #{child["isEdited"] == true ? translate(locale, "(edited)") : ""}</span> <span title="#{Time.unix(child["published"].as_i64).to_s(I18n.translate(locale, "%A %B %-d, %Y"))}">#{I18n.translate(locale, "`x` ago", recode_date(Time.unix(child["published"].as_i64), locale))} #{child["isEdited"] == true ? I18n.translate(locale, "(edited)") : ""}</span>
| |
END_HTML END_HTML
if comments["videoId"]? if comments["videoId"]?
html << <<-END_HTML html << <<-END_HTML
<a rel="noreferrer noopener" href="https://www.youtube.com/watch?v=#{comments["videoId"]}&lc=#{child["commentId"]}" title="#{translate(locale, "YouTube comment permalink")}">[YT]</a> <a rel="noreferrer noopener" href="https://www.youtube.com/watch?v=#{comments["videoId"]}&lc=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
| |
END_HTML END_HTML
elsif comments["authorId"]? elsif comments["authorId"]?
html << <<-END_HTML html << <<-END_HTML
<a rel="noreferrer noopener" href="https://www.youtube.com/channel/#{comments["authorId"]}/community?lb=#{child["commentId"]}" title="#{translate(locale, "YouTube comment permalink")}">[YT]</a> <a rel="noreferrer noopener" href="https://www.youtube.com/channel/#{comments["authorId"]}/community?lb=#{child["commentId"]}" title="#{I18n.translate(locale, "YouTube comment permalink")}">[YT]</a>
| |
END_HTML END_HTML
end end
@ -172,7 +172,7 @@ module Invidious::Frontend::Comments
html << <<-END_HTML html << <<-END_HTML
&nbsp; &nbsp;
<span class="creator-heart-container" title="#{translate(locale, "`x` marked it with a ❤", child["creatorHeart"]["creatorName"].as_s)}"> <span class="creator-heart-container" title="#{I18n.translate(locale, "`x` marked it with a ❤", child["creatorHeart"]["creatorName"].as_s)}">
<span class="creator-heart"> <span class="creator-heart">
<img loading="lazy" class="creator-heart-background-hearted" src="#{creator_thumbnail}" alt="" /> <img loading="lazy" class="creator-heart-background-hearted" src="#{creator_thumbnail}" alt="" />
<span class="creator-heart-small-hearted"> <span class="creator-heart-small-hearted">
@ -197,7 +197,7 @@ module Invidious::Frontend::Comments
<div class="pure-u-1"> <div class="pure-u-1">
<p> <p>
<a href="javascript:void(0)" data-continuation="#{comments["continuation"]}" <a href="javascript:void(0)" data-continuation="#{comments["continuation"]}"
data-onclick="get_youtube_replies" data-load-more #{"data-load-replies" if is_replies}>#{translate(locale, "Load more")}</a> data-onclick="get_youtube_replies" data-load-more #{"data-load-replies" if is_replies}>#{I18n.translate(locale, "Load more")}</a>
</p> </p>
</div> </div>
</div> </div>

View File

@ -6,16 +6,16 @@ module Invidious::Frontend::Pagination
private def first_page(str : String::Builder, locale : String?, url : String) private def first_page(str : String::Builder, locale : String?, url : String)
str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">) str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">)
if locale_is_rtl?(locale) if I18n.locale_is_rtl?(locale)
# Inverted arrow ("first" points to the right) # Inverted arrow ("first" points to the right)
str << translate(locale, "First page") str << I18n.translate(locale, "First page")
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << %(<i class="icon ion-ios-arrow-forward"></i>) str << %(<i class="icon ion-ios-arrow-forward"></i>)
else else
# Regular arrow ("first" points to the left) # Regular arrow ("first" points to the left)
str << %(<i class="icon ion-ios-arrow-back"></i>) str << %(<i class="icon ion-ios-arrow-back"></i>)
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << translate(locale, "First page") str << I18n.translate(locale, "First page")
end end
str << "</a>" str << "</a>"
@ -25,16 +25,16 @@ module Invidious::Frontend::Pagination
# Link # Link
str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">) str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">)
if locale_is_rtl?(locale) if I18n.locale_is_rtl?(locale)
# Inverted arrow ("previous" points to the right) # Inverted arrow ("previous" points to the right)
str << translate(locale, "Previous page") str << I18n.translate(locale, "Previous page")
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << %(<i class="icon ion-ios-arrow-forward"></i>) str << %(<i class="icon ion-ios-arrow-forward"></i>)
else else
# Regular arrow ("previous" points to the left) # Regular arrow ("previous" points to the left)
str << %(<i class="icon ion-ios-arrow-back"></i>) str << %(<i class="icon ion-ios-arrow-back"></i>)
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << translate(locale, "Previous page") str << I18n.translate(locale, "Previous page")
end end
str << "</a>" str << "</a>"
@ -44,14 +44,14 @@ module Invidious::Frontend::Pagination
# Link # Link
str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">) str << %(<a href=") << url << %(" class="pure-button pure-button-secondary">)
if locale_is_rtl?(locale) if I18n.locale_is_rtl?(locale)
# Inverted arrow ("next" points to the left) # Inverted arrow ("next" points to the left)
str << %(<i class="icon ion-ios-arrow-back"></i>) str << %(<i class="icon ion-ios-arrow-back"></i>)
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << translate(locale, "Next page") str << I18n.translate(locale, "Next page")
else else
# Regular arrow ("next" points to the right) # Regular arrow ("next" points to the right)
str << translate(locale, "Next page") str << I18n.translate(locale, "Next page")
str << "&nbsp;&nbsp;" str << "&nbsp;&nbsp;"
str << %(<i class="icon ion-ios-arrow-forward"></i>) str << %(<i class="icon ion-ios-arrow-forward"></i>)
end end

View File

@ -6,7 +6,7 @@ module Invidious::Frontend::SearchFilters
return String.build(8000) do |str| return String.build(8000) do |str|
str << "<div id='filters'>\n" str << "<div id='filters'>\n"
str << "\t<details id='filters-collapse'>" str << "\t<details id='filters-collapse'>"
str << "\t\t<summary>" << translate(locale, "search_filters_title") << "</summary>\n" str << "\t\t<summary>" << I18n.translate(locale, "search_filters_title") << "</summary>\n"
str << "\t\t<div id='filters-box'><form action='/search' method='get'>\n" str << "\t\t<div id='filters-box'><form action='/search' method='get'>\n"
@ -25,7 +25,7 @@ module Invidious::Frontend::SearchFilters
str << "\t\t\t<div id='filters-apply'>" str << "\t\t\t<div id='filters-apply'>"
str << "<button type='submit' class=\"pure-button pure-button-primary\">" str << "<button type='submit' class=\"pure-button pure-button-primary\">"
str << translate(locale, "search_filters_apply_button") str << I18n.translate(locale, "search_filters_apply_button")
str << "</button></div>\n" str << "</button></div>\n"
str << "\t\t</form></div>\n" str << "\t\t</form></div>\n"
@ -41,7 +41,7 @@ module Invidious::Frontend::SearchFilters
str << "\t\t\t\t<div class=\"filter-column\"><fieldset>\n" str << "\t\t\t\t<div class=\"filter-column\"><fieldset>\n"
str << "\t\t\t\t\t<legend><div class=\"filter-name underlined\">" str << "\t\t\t\t\t<legend><div class=\"filter-name underlined\">"
str << translate(locale, "search_filters_{{name}}_label") str << I18n.translate(locale, "search_filters_{{name}}_label")
str << "</div></legend>\n" str << "</div></legend>\n"
str << "\t\t\t\t\t<div class=\"filter-options\">\n" str << "\t\t\t\t\t<div class=\"filter-options\">\n"
@ -62,7 +62,7 @@ module Invidious::Frontend::SearchFilters
str << '>' str << '>'
str << "<label for='filter-date-{{date}}'>" str << "<label for='filter-date-{{date}}'>"
str << translate(locale, "search_filters_date_option_{{date}}") str << I18n.translate(locale, "search_filters_date_option_{{date}}")
str << "</label></div>\n" str << "</label></div>\n"
{% end %} {% end %}
end end
@ -78,7 +78,7 @@ module Invidious::Frontend::SearchFilters
str << '>' str << '>'
str << "<label for='filter-type-{{type}}'>" str << "<label for='filter-type-{{type}}'>"
str << translate(locale, "search_filters_type_option_{{type}}") str << I18n.translate(locale, "search_filters_type_option_{{type}}")
str << "</label></div>\n" str << "</label></div>\n"
{% end %} {% end %}
end end
@ -94,7 +94,7 @@ module Invidious::Frontend::SearchFilters
str << '>' str << '>'
str << "<label for='filter-duration-{{duration}}'>" str << "<label for='filter-duration-{{duration}}'>"
str << translate(locale, "search_filters_duration_option_{{duration}}") str << I18n.translate(locale, "search_filters_duration_option_{{duration}}")
str << "</label></div>\n" str << "</label></div>\n"
{% end %} {% end %}
end end
@ -111,7 +111,7 @@ module Invidious::Frontend::SearchFilters
str << '>' str << '>'
str << "<label for='filter-feature-{{feature}}'>" str << "<label for='filter-feature-{{feature}}'>"
str << translate(locale, "search_filters_features_option_{{feature}}") str << I18n.translate(locale, "search_filters_features_option_{{feature}}")
str << "</label></div>\n" str << "</label></div>\n"
{% end %} {% end %}
{% end %} {% end %}
@ -128,7 +128,7 @@ module Invidious::Frontend::SearchFilters
str << '>' str << '>'
str << "<label for='filter-sort-{{sort}}'>" str << "<label for='filter-sort-{{sort}}'>"
str << translate(locale, "search_filters_sort_option_{{sort}}") str << I18n.translate(locale, "search_filters_sort_option_{{sort}}")
str << "</label></div>\n" str << "</label></div>\n"
{% end %} {% end %}
end end

View File

@ -20,11 +20,11 @@ module Invidious::Frontend::WatchPage
def download_widget(locale : String, video : Video, video_assets : VideoAssets) : String def download_widget(locale : String, video : Video, video_assets : VideoAssets) : String
if CONFIG.disabled?("downloads") if CONFIG.disabled?("downloads")
return "<p id=\"download\">#{translate(locale, "Download is disabled")}</p>" return "<p id=\"download\">#{I18n.translate(locale, "Download is disabled")}</p>"
end end
if CONFIG.dmca_content.includes?(video.id) if CONFIG.dmca_content.includes?(video.id)
return "<p id=\"download\">#{translate(locale, "dmca_content")}</p>" return "<p id=\"download\">#{I18n.translate(locale, "dmca_content")}</p>"
end end
url = "/download" url = "/download"
@ -49,7 +49,7 @@ module Invidious::Frontend::WatchPage
str << "\t<div class=\"pure-control-group\">\n" str << "\t<div class=\"pure-control-group\">\n"
str << "\t\t<label for='download_widget'>" str << "\t\t<label for='download_widget'>"
str << translate(locale, "Download as: ") str << I18n.translate(locale, "Download as: ")
str << "</label>\n" str << "</label>\n"
str << "\t\t<select name='download_widget' id='download_widget'>\n" str << "\t\t<select name='download_widget' id='download_widget'>\n"
@ -98,7 +98,7 @@ module Invidious::Frontend::WatchPage
value = {"label": caption.name, "ext": "#{caption.language_code}.vtt"}.to_json value = {"label": caption.name, "ext": "#{caption.language_code}.vtt"}.to_json
str << "\t\t\t<option value='" << value << "'>" str << "\t\t\t<option value='" << value << "'>"
str << translate(locale, "download_subtitles", translate(locale, caption.name)) str << I18n.translate(locale, "download_subtitles", I18n.translate(locale, caption.name))
str << "</option>\n" str << "</option>\n"
end end
@ -108,7 +108,7 @@ module Invidious::Frontend::WatchPage
str << "\t</div>\n" str << "\t</div>\n"
str << "\t<button type=\"submit\" class=\"pure-button pure-button-primary\">\n" str << "\t<button type=\"submit\" class=\"pure-button pure-button-primary\">\n"
str << "\t\t<b>" << translate(locale, "Download") << "</b>\n" str << "\t\t<b>" << I18n.translate(locale, "Download") << "</b>\n"
str << "\t</button>\n" str << "\t</button>\n"
str << "</form>\n" str << "</form>\n"

View File

@ -63,19 +63,19 @@ def error_template_helper(env : HTTP::Server::Context, status_code : Int32, exce
error_message = <<-END_HTML error_message = <<-END_HTML
<div class="error_message"> <div class="error_message">
<h2>#{translate(locale, "crash_page_you_found_a_bug")}</h2> <h2>#{I18n.translate(locale, "crash_page_you_found_a_bug")}</h2>
<br/><br/> <br/><br/>
<p><b>#{translate(locale, "crash_page_before_reporting")}</b></p> <p><b>#{I18n.translate(locale, "crash_page_before_reporting")}</b></p>
<ul> <ul>
<li>#{translate(locale, "crash_page_refresh", env.request.resource)}</li> <li>#{I18n.translate(locale, "crash_page_refresh", env.request.resource)}</li>
<li>#{translate(locale, "crash_page_switch_instance", url_switch)}</li> <li>#{I18n.translate(locale, "crash_page_switch_instance", url_switch)}</li>
<li>#{translate(locale, "crash_page_read_the_faq", url_faq)}</li> <li>#{I18n.translate(locale, "crash_page_read_the_faq", url_faq)}</li>
<li>#{translate(locale, "crash_page_search_issue", url_search_issues)}</li> <li>#{I18n.translate(locale, "crash_page_search_issue", url_search_issues)}</li>
</ul> </ul>
<br/> <br/>
<p>#{translate(locale, "crash_page_report_issue", url_new_issue)}</p> <p>#{I18n.translate(locale, "crash_page_report_issue", url_new_issue)}</p>
<!-- TODO: Add a "copy to clipboard" button --> <!-- TODO: Add a "copy to clipboard" button -->
<pre class="error-issue-template">#{issue_template}</pre> <pre class="error-issue-template">#{issue_template}</pre>
@ -95,7 +95,7 @@ def error_template_helper(env : HTTP::Server::Context, status_code : Int32, mess
locale = env.get("preferences").as(Preferences).locale locale = env.get("preferences").as(Preferences).locale
error_message = translate(locale, message) error_message = I18n.translate(locale, message)
next_steps = error_redirect_helper(env) next_steps = error_redirect_helper(env)
return templated "error" return templated "error"
@ -186,10 +186,10 @@ def error_redirect_helper(env : HTTP::Server::Context)
if request_path.starts_with?("/search") || request_path.starts_with?("/watch") || if request_path.starts_with?("/search") || request_path.starts_with?("/watch") ||
request_path.starts_with?("/channel") || request_path.starts_with?("/playlist?list=PL") request_path.starts_with?("/channel") || request_path.starts_with?("/playlist?list=PL")
next_steps_text = translate(locale, "next_steps_error_message") next_steps_text = I18n.translate(locale, "next_steps_error_message")
refresh = translate(locale, "next_steps_error_message_refresh") refresh = I18n.translate(locale, "next_steps_error_message_refresh")
go_to_youtube = translate(locale, "next_steps_error_message_go_to_youtube") go_to_youtube = I18n.translate(locale, "next_steps_error_message_go_to_youtube")
switch_instance = translate(locale, "Switch Invidious Instance") switch_instance = I18n.translate(locale, "Switch Invidious Instance")
return <<-END_HTML return <<-END_HTML
<p style="margin-bottom: 4px;">#{next_steps_text}</p> <p style="margin-bottom: 4px;">#{next_steps_text}</p>

View File

@ -1,199 +1,203 @@
# Languages requiring a better level of translation (at least 20%) module I18n
# to be added to the list below: extend self
#
# "af" => "", # Afrikaans
# "az" => "", # Azerbaijani
# "be" => "", # Belarusian
# "bn_BD" => "", # Bengali (Bangladesh)
# "ia" => "", # Interlingua
# "or" => "", # Odia
# "tk" => "", # Turkmen
# "tok => "", # Toki Pona
#
LOCALES_LIST = {
"ar" => "العربية", # Arabic
"bg" => "български", # Bulgarian
"bn" => "বাংলা", # Bengali
"ca" => "Català", # Catalan
"cs" => "Čeština", # Czech
"cy" => "Cymraeg", # Welsh
"da" => "Dansk", # Danish
"de" => "Deutsch", # German
"el" => "Ελληνικά", # Greek
"en-US" => "English", # English
"eo" => "Esperanto", # Esperanto
"es" => "Español", # Spanish
"et" => "Eesti keel", # Estonian
"eu" => "Euskara", # Basque
"fa" => "فارسی", # Persian
"fi" => "Suomi", # Finnish
"fr" => "Français", # French
"he" => "עברית", # Hebrew
"hi" => "हिन्दी", # Hindi
"hr" => "Hrvatski", # Croatian
"hu-HU" => "Magyar Nyelv", # Hungarian
"id" => "Bahasa Indonesia", # Indonesian
"is" => "Íslenska", # Icelandic
"it" => "Italiano", # Italian
"ja" => "日本語", # Japanese
"ko" => "한국어", # Korean
"lmo" => "Lombard", # Lombard
"lt" => "Lietuvių", # Lithuanian
"nb-NO" => "Norsk bokmål", # Norwegian Bokmål
"nl" => "Nederlands", # Dutch
"pl" => "Polski", # Polish
"pt" => "Português", # Portuguese
"pt-BR" => "Português Brasileiro", # Portuguese (Brazil)
"pt-PT" => "Português de Portugal", # Portuguese (Portugal)
"ro" => "Română", # Romanian
"ru" => "Русский", # Russian
"si" => "සිංහල", # Sinhala
"sk" => "Slovenčina", # Slovak
"sl" => "Slovenščina", # Slovenian
"sq" => "Shqip", # Albanian
"sr" => "Srpski (latinica)", # Serbian (Latin)
"sr_Cyrl" => "Српски (ћирилица)", # Serbian (Cyrillic)
"sv-SE" => "Svenska", # Swedish
"ta" => "தமிழ்", # Tamil
"tr" => "Türkçe", # Turkish
"uk" => "Українська", # Ukrainian
"vi" => "Tiếng Việt", # Vietnamese
"zh-CN" => "汉语", # Chinese (Simplified)
"zh-TW" => "漢語", # Chinese (Traditional)
}
LOCALES = load_all_locales() # Languages requiring a better level of translation (at least 20%)
# to be added to the list below:
#
# "af" => "", # Afrikaans
# "az" => "", # Azerbaijani
# "be" => "", # Belarusian
# "bn_BD" => "", # Bengali (Bangladesh)
# "ia" => "", # Interlingua
# "or" => "", # Odia
# "tk" => "", # Turkmen
# "tok => "", # Toki Pona
#
LOCALES_LIST = {
"ar" => "العربية", # Arabic
"bg" => "български", # Bulgarian
"bn" => "বাংলা", # Bengali
"ca" => "Català", # Catalan
"cs" => "Čeština", # Czech
"cy" => "Cymraeg", # Welsh
"da" => "Dansk", # Danish
"de" => "Deutsch", # German
"el" => "Ελληνικά", # Greek
"en-US" => "English", # English
"eo" => "Esperanto", # Esperanto
"es" => "Español", # Spanish
"et" => "Eesti keel", # Estonian
"eu" => "Euskara", # Basque
"fa" => "فارسی", # Persian
"fi" => "Suomi", # Finnish
"fr" => "Français", # French
"he" => "עברית", # Hebrew
"hi" => "हिन्दी", # Hindi
"hr" => "Hrvatski", # Croatian
"hu-HU" => "Magyar Nyelv", # Hungarian
"id" => "Bahasa Indonesia", # Indonesian
"is" => "Íslenska", # Icelandic
"it" => "Italiano", # Italian
"ja" => "日本語", # Japanese
"ko" => "한국어", # Korean
"lmo" => "Lombard", # Lombard
"lt" => "Lietuvių", # Lithuanian
"nb-NO" => "Norsk bokmål", # Norwegian Bokmål
"nl" => "Nederlands", # Dutch
"pl" => "Polski", # Polish
"pt" => "Português", # Portuguese
"pt-BR" => "Português Brasileiro", # Portuguese (Brazil)
"pt-PT" => "Português de Portugal", # Portuguese (Portugal)
"ro" => "Română", # Romanian
"ru" => "Русский", # Russian
"si" => "සිංහල", # Sinhala
"sk" => "Slovenčina", # Slovak
"sl" => "Slovenščina", # Slovenian
"sq" => "Shqip", # Albanian
"sr" => "Srpski (latinica)", # Serbian (Latin)
"sr_Cyrl" => "Српски (ћирилица)", # Serbian (Cyrillic)
"sv-SE" => "Svenska", # Swedish
"ta" => "தமிழ்", # Tamil
"tr" => "Türkçe", # Turkish
"uk" => "Українська", # Ukrainian
"vi" => "Tiếng Việt", # Vietnamese
"zh-CN" => "汉语", # Chinese (Simplified)
"zh-TW" => "漢語", # Chinese (Traditional)
}
CONTENT_REGIONS = { LOCALES = load_all_locales()
"AE", "AR", "AT", "AU", "AZ", "BA", "BD", "BE", "BG", "BH", "BO", "BR", "BY",
"CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE",
"EG", "ES", "FI", "FR", "GB", "GE", "GH", "GR", "GT", "HK", "HN", "HR", "HU",
"ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KR", "KW",
"KZ", "LB", "LI", "LK", "LT", "LU", "LV", "LY", "MA", "ME", "MK", "MT", "MX",
"MY", "NG", "NI", "NL", "NO", "NP", "NZ", "OM", "PA", "PE", "PG", "PH", "PK",
"PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU", "SA", "SE", "SG", "SI", "SK",
"SN", "SV", "TH", "TN", "TR", "TW", "TZ", "UA", "UG", "US", "UY", "VE", "VN",
"YE", "ZA", "ZW",
}
# Enum for the different types of number formats CONTENT_REGIONS = {
enum NumberFormatting "AE", "AR", "AT", "AU", "AZ", "BA", "BD", "BE", "BG", "BH", "BO", "BR", "BY",
None # Print the number as-is "CA", "CH", "CL", "CO", "CR", "CY", "CZ", "DE", "DK", "DO", "DZ", "EC", "EE",
Separator # Use a separator for thousands "EG", "ES", "FI", "FR", "GB", "GE", "GH", "GR", "GT", "HK", "HN", "HR", "HU",
Short # Use short notation (k/M/B) "ID", "IE", "IL", "IN", "IQ", "IS", "IT", "JM", "JO", "JP", "KE", "KR", "KW",
HtmlSpan # Surround with <span id="count"></span> "KZ", "LB", "LI", "LK", "LT", "LU", "LV", "LY", "MA", "ME", "MK", "MT", "MX",
end "MY", "NG", "NI", "NL", "NO", "NP", "NZ", "OM", "PA", "PE", "PG", "PH", "PK",
"PL", "PR", "PT", "PY", "QA", "RO", "RS", "RU", "SA", "SE", "SG", "SI", "SK",
"SN", "SV", "TH", "TN", "TR", "TW", "TZ", "UA", "UG", "US", "UY", "VE", "VN",
"YE", "ZA", "ZW",
}
def load_all_locales # Enum for the different types of number formats
locales = {} of String => Hash(String, JSON::Any) enum NumberFormatting
None # Print the number as-is
LOCALES_LIST.each_key do |name| Separator # Use a separator for thousands
locales[name] = JSON.parse(File.read("locales/#{name}.json")).as_h Short # Use short notation (k/M/B)
HtmlSpan # Surround with <span id="count"></span>
end end
return locales def load_all_locales
end locales = {} of String => Hash(String, JSON::Any)
def translate(locale : String?, key : String, text : String | Hash(String, String) | Nil = nil) : String LOCALES_LIST.each_key do |name|
# Log a warning if "key" doesn't exist in en-US locale and return locales[name] = JSON.parse(File.read("locales/#{name}.json")).as_h
# that key as the text, so this is more or less transparent to the user.
if !LOCALES["en-US"].has_key?(key)
LOGGER.warn("i18n: Missing translation key \"#{key}\"")
return key
end
# Default to english, whenever the locale doesn't exist,
# or the key requested has not been translated
if locale && LOCALES.has_key?(locale) && LOCALES[locale].has_key?(key)
raw_data = LOCALES[locale][key]
else
raw_data = LOCALES["en-US"][key]
end
case raw_data
when .as_h?
# Init
translation = ""
match_length = 0
raw_data.as_h.each do |hash_key, value|
if text.is_a?(String)
if md = text.try &.match(/#{hash_key}/)
if md[0].size >= match_length
translation = value.as_s
match_length = md[0].size
end
end
end
end end
when .as_s?
translation = raw_data.as_s return locales
else
raise "Invalid translation \"#{raw_data}\""
end end
if text.is_a?(String) def translate(locale : String?, key : String, text : String | Hash(String, String) | Nil = nil) : String
translation = translation.gsub("`x`", text) # Log a warning if "key" doesn't exist in en-US locale and return
elsif text.is_a?(Hash(String, String)) # that key as the text, so this is more or less transparent to the user.
# adds support for multi string interpolation. Based on i18next https://www.i18next.com/translation-function/interpolation#basic if !LOCALES["en-US"].has_key?(key)
text.each_key do |hash_key|
translation = translation.gsub("{{#{hash_key}}}", text[hash_key])
end
end
return translation
end
def translate_count(locale : String, key : String, count : Int, format = NumberFormatting::None) : String
# Fallback on english if locale doesn't exist
locale = "en-US" if !LOCALES.has_key?(locale)
# Retrieve suffix
suffix = I18next::Plurals::RESOLVER.get_suffix(locale, count)
plural_key = key + suffix
if LOCALES[locale].has_key?(plural_key)
translation = LOCALES[locale][plural_key].as_s
else
# Try #1: Fallback to singular in the same locale
singular_suffix = I18next::Plurals::RESOLVER.get_suffix(locale, 1)
if LOCALES[locale].has_key?(key + singular_suffix)
translation = LOCALES[locale][key + singular_suffix].as_s
elsif locale != "en-US"
# Try #2: Fallback to english
translation = translate_count("en-US", key, count)
else
# Return key if we're already in english, as the translation is missing
LOGGER.warn("i18n: Missing translation key \"#{key}\"") LOGGER.warn("i18n: Missing translation key \"#{key}\"")
return key return key
end end
# Default to english, whenever the locale doesn't exist,
# or the key requested has not been translated
if locale && LOCALES.has_key?(locale) && LOCALES[locale].has_key?(key)
raw_data = LOCALES[locale][key]
else
raw_data = LOCALES["en-US"][key]
end
case raw_data
when .as_h?
# Init
translation = ""
match_length = 0
raw_data.as_h.each do |hash_key, value|
if text.is_a?(String)
if md = text.try &.match(/#{hash_key}/)
if md[0].size >= match_length
translation = value.as_s
match_length = md[0].size
end
end
end
end
when .as_s?
translation = raw_data.as_s
else
raise "Invalid translation \"#{raw_data}\""
end
if text.is_a?(String)
translation = translation.gsub("`x`", text)
elsif text.is_a?(Hash(String, String))
# adds support for multi string interpolation. Based on i18next https://www.i18next.com/translation-function/interpolation#basic
text.each_key do |hash_key|
translation = translation.gsub("{{#{hash_key}}}", text[hash_key])
end
end
return translation
end end
case format def translate_count(locale : String, key : String, count : Int, format = NumberFormatting::None) : String
when .separator? then count_txt = number_with_separator(count) # Fallback on english if locale doesn't exist
when .short? then count_txt = number_to_short_text(count) locale = "en-US" if !LOCALES.has_key?(locale)
when .html_span? then count_txt = "<span id=\"count\">" + count.to_s + "</span>"
else count_txt = count.to_s # Retrieve suffix
suffix = I18next::Plurals::RESOLVER.get_suffix(locale, count)
plural_key = key + suffix
if LOCALES[locale].has_key?(plural_key)
translation = LOCALES[locale][plural_key].as_s
else
# Try #1: Fallback to singular in the same locale
singular_suffix = I18next::Plurals::RESOLVER.get_suffix(locale, 1)
if LOCALES[locale].has_key?(key + singular_suffix)
translation = LOCALES[locale][key + singular_suffix].as_s
elsif locale != "en-US"
# Try #2: Fallback to english
translation = self.translate_count("en-US", key, count)
else
# Return key if we're already in english, as the translation is missing
LOGGER.warn("i18n: Missing translation key \"#{key}\"")
return key
end
end
case format
when .separator? then count_txt = number_with_separator(count)
when .short? then count_txt = number_to_short_text(count)
when .html_span? then count_txt = "<span id=\"count\">" + count.to_s + "</span>"
else count_txt = count.to_s
end
return translation.gsub("{{count}}", count_txt)
end end
return translation.gsub("{{count}}", count_txt) def translate_bool(locale : String?, translation : Bool)
end case translation
when true
return self.translate(locale, "Yes")
when false
return self.translate(locale, "No")
end
end
def translate_bool(locale : String?, translation : Bool) def locale_is_rtl?(locale : String?)
case translation # Fallback to en-US
when true return false if locale.nil?
return translate(locale, "Yes")
when false # Arabic, Persian, Hebrew
return translate(locale, "No") # See https://en.wikipedia.org/wiki/Right-to-left_script#List_of_RTL_scripts
return {"ar", "fa", "he"}.includes? locale
end end
end end
def locale_is_rtl?(locale : String?)
# Fallback to en-US
return false if locale.nil?
# Arabic, Persian, Hebrew
# See https://en.wikipedia.org/wiki/Right-to-left_script#List_of_RTL_scripts
return {"ar", "fa", "he"}.includes? locale
end

View File

@ -115,9 +115,9 @@ struct SearchVideo
json.field "descriptionHtml", self.description_html json.field "descriptionHtml", self.description_html
json.field "viewCount", self.views json.field "viewCount", self.views
json.field "viewCountText", translate_count(locale, "generic_views_count", self.views, NumberFormatting::Short) json.field "viewCountText", I18n.translate_count(locale, "generic_views_count", self.views, I18n::NumberFormatting::Short)
json.field "published", self.published.to_unix json.field "published", self.published.to_unix
json.field "publishedText", translate(locale, "`x` ago", recode_date(self.published, locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(self.published, locale))
json.field "lengthSeconds", self.length_seconds json.field "lengthSeconds", self.length_seconds
json.field "liveNow", self.badges.live_now? json.field "liveNow", self.badges.live_now?
json.field "premium", self.badges.premium? json.field "premium", self.badges.premium?
@ -327,8 +327,8 @@ struct ProblematicTimelineItem
xml.element("content", type: "xhtml") do xml.element("content", type: "xhtml") do
xml.element("div", xmlns: "http://www.w3.org/1999/xhtml") do xml.element("div", xmlns: "http://www.w3.org/1999/xhtml") do
xml.element("div") do xml.element("div") do
xml.element("h4") { translate(locale, "timeline_parse_error_placeholder_heading") } xml.element("h4") { I18n.translate(locale, "timeline_parse_error_placeholder_heading") }
xml.element("p") { translate(locale, "timeline_parse_error_placeholder_message") } xml.element("p") { I18n.translate(locale, "timeline_parse_error_placeholder_message") }
end end
xml.element("pre") do xml.element("pre") do

View File

@ -146,19 +146,19 @@ def recode_date(time : Time, locale)
span = Time.utc - time span = Time.utc - time
if span.total_days > 365.0 if span.total_days > 365.0
return translate_count(locale, "generic_count_years", span.total_days.to_i // 365) return I18n.translate_count(locale, "generic_count_years", span.total_days.to_i // 365)
elsif span.total_days > 30.0 elsif span.total_days > 30.0
return translate_count(locale, "generic_count_months", span.total_days.to_i // 30) return I18n.translate_count(locale, "generic_count_months", span.total_days.to_i // 30)
elsif span.total_days > 7.0 elsif span.total_days > 7.0
return translate_count(locale, "generic_count_weeks", span.total_days.to_i // 7) return I18n.translate_count(locale, "generic_count_weeks", span.total_days.to_i // 7)
elsif span.total_hours > 24.0 elsif span.total_hours > 24.0
return translate_count(locale, "generic_count_days", span.total_days.to_i) return I18n.translate_count(locale, "generic_count_days", span.total_days.to_i)
elsif span.total_minutes > 60.0 elsif span.total_minutes > 60.0
return translate_count(locale, "generic_count_hours", span.total_hours.to_i) return I18n.translate_count(locale, "generic_count_hours", span.total_hours.to_i)
elsif span.total_seconds > 60.0 elsif span.total_seconds > 60.0
return translate_count(locale, "generic_count_minutes", span.total_minutes.to_i) return I18n.translate_count(locale, "generic_count_minutes", span.total_minutes.to_i)
else else
return translate_count(locale, "generic_count_seconds", span.total_seconds.to_i) return I18n.translate_count(locale, "generic_count_seconds", span.total_seconds.to_i)
end end
end end

View File

@ -22,7 +22,7 @@ module Invidious::JSONify::APIv1
json.field "description", video.description json.field "description", video.description
json.field "descriptionHtml", video.description_html json.field "descriptionHtml", video.description_html
json.field "published", video.published.to_unix json.field "published", video.published.to_unix
json.field "publishedText", translate(locale, "`x` ago", recode_date(video.published, locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(video.published, locale))
json.field "keywords", video.keywords json.field "keywords", video.keywords
json.field "viewCount", video.views json.field "viewCount", video.views
@ -268,7 +268,7 @@ module Invidious::JSONify::APIv1
json.field "viewCountText", rv["short_view_count"]? json.field "viewCountText", rv["short_view_count"]?
json.field "published", rv["published"]? json.field "published", rv["published"]?
if rv["published"]?.try &.presence if rv["published"]?.try &.presence
json.field "publishedText", translate(locale, "`x` ago", recode_date(Time.parse_rfc3339(rv["published"].to_s), locale)) json.field "publishedText", I18n.translate(locale, "`x` ago", recode_date(Time.parse_rfc3339(rv["published"].to_s), locale))
else else
json.field "publishedText", "" json.field "publishedText", ""
end end

View File

@ -19,7 +19,7 @@ module Invidious::Routes::BeforeAll
preferences = Preferences.from_json(URI.decode_www_form(prefs_cookie.value)) preferences = Preferences.from_json(URI.decode_www_form(prefs_cookie.value))
else else
if language_header = env.request.headers["Accept-Language"]? if language_header = env.request.headers["Accept-Language"]?
if language = ANG.language_negotiator.best(language_header, LOCALES.keys) if language = ANG.language_negotiator.best(language_header, I18n::LOCALES.keys)
preferences.locale = language.header preferences.locale = language.header
end end
end end

View File

@ -354,7 +354,7 @@ module Invidious::Routes::Channels
resolved_url = YoutubeAPI.resolve_url("https://youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}") resolved_url = YoutubeAPI.resolve_url("https://youtube.com#{env.request.path}#{yt_url_params.size > 0 ? "?#{yt_url_params}" : ""}")
ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"] ucid = resolved_url["endpoint"]["browseEndpoint"]["browseId"]
rescue ex : InfoException | KeyError rescue ex : InfoException | KeyError
return error_template(404, translate(locale, "This channel does not exist.")) return error_template(404, I18n.translate(locale, "This channel does not exist."))
end end
selected_tab = env.params.url["tab"]? selected_tab = env.params.url["tab"]?

View File

@ -10,7 +10,7 @@ module Invidious::Routes::Embed
videos = get_playlist_videos(playlist, offset: offset) videos = get_playlist_videos(playlist, offset: offset)
if videos.empty? if videos.empty?
url = "/playlist?list=#{plid}" url = "/playlist?list=#{plid}"
raise NotFoundException.new(translate(locale, "error_video_not_in_playlist", url)) raise NotFoundException.new(I18n.translate(locale, "error_video_not_in_playlist", url))
end end
first_playlist_video = videos[0].as(PlaylistVideo) first_playlist_video = videos[0].as(PlaylistVideo)
@ -71,7 +71,7 @@ module Invidious::Routes::Embed
videos = get_playlist_videos(playlist, offset: offset) videos = get_playlist_videos(playlist, offset: offset)
if videos.empty? if videos.empty?
url = "/playlist?list=#{plid}" url = "/playlist?list=#{plid}"
raise NotFoundException.new(translate(locale, "error_video_not_in_playlist", url)) raise NotFoundException.new(I18n.translate(locale, "error_video_not_in_playlist", url))
end end
first_playlist_video = videos[0].as(PlaylistVideo) first_playlist_video = videos[0].as(PlaylistVideo)

View File

@ -37,7 +37,7 @@ module Invidious::Routes::Feeds
if CONFIG.popular_enabled if CONFIG.popular_enabled
templated "feeds/popular" templated "feeds/popular"
else else
message = translate(locale, "The Popular feed has been disabled by the administrator.") message = I18n.translate(locale, "The Popular feed has been disabled by the administrator.")
templated "message" templated "message"
end end
end end
@ -259,7 +259,7 @@ module Invidious::Routes::Feeds
xml.element("link", "type": "text/html", rel: "alternate", href: "#{HOST_URL}/feed/subscriptions") xml.element("link", "type": "text/html", rel: "alternate", href: "#{HOST_URL}/feed/subscriptions")
xml.element("link", "type": "application/atom+xml", rel: "self", xml.element("link", "type": "application/atom+xml", rel: "self",
href: "#{HOST_URL}#{env.request.resource}") href: "#{HOST_URL}#{env.request.resource}")
xml.element("title") { xml.text translate(locale, "Invidious Private Feed for `x`", user.email) } xml.element("title") { xml.text I18n.translate(locale, "Invidious Private Feed for `x`", user.email) }
(notifications + videos).each do |video| (notifications + videos).each do |video|
video.to_xml(locale, params, xml) video.to_xml(locale, params, xml)

View File

@ -112,7 +112,7 @@ module Invidious::Routes::Login
user, sid = create_user(sid, email, password) user, sid = create_user(sid, email, password)
if language_header = env.request.headers["Accept-Language"]? if language_header = env.request.headers["Accept-Language"]?
if language = ANG.language_negotiator.best(language_header, LOCALES.keys) if language = ANG.language_negotiator.best(language_header, I18n::LOCALES.keys)
user.preferences.locale = language.header user.preferences.locale = language.header
end end
end end

View File

@ -8,12 +8,12 @@
<div class="pure-u-1 pure-u-lg-3-5"> <div class="pure-u-1 pure-u-lg-3-5">
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/add_playlist_items" method="get"> <form class="pure-form pure-form-aligned" action="/add_playlist_items" method="get">
<legend><a href="/playlist?list=<%= playlist.id %>"><%= translate(locale, "Editing playlist `x`", %|"#{HTML.escape(playlist.title)}"|) %></a></legend> <legend><a href="/playlist?list=<%= playlist.id %>"><%= I18n.translate(locale, "Editing playlist `x`", %|"#{HTML.escape(playlist.title)}"|) %></a></legend>
<fieldset> <fieldset>
<input class="pure-input-1" type="search" name="q" <input class="pure-input-1" type="search" name="q"
<% if query %>value="<%= HTML.escape(query.text) %>"<% end %> <% if query %>value="<%= HTML.escape(query.text) %>"<% end %>
placeholder="<%= translate(locale, "Search for videos") %>"> placeholder="<%= I18n.translate(locale, "Search for videos") %>">
<input type="hidden" name="list" value="<%= plid %>"> <input type="hidden" name="list" value="<%= plid %>">
</fieldset> </fieldset>
</form> </form>

View File

@ -35,10 +35,10 @@
<%= <%=
{ {
"ucid" => ucid, "ucid" => ucid,
"youtube_comments_text" => HTML.escape(translate(locale, "View YouTube comments")), "youtube_comments_text" => HTML.escape(I18n.translate(locale, "View YouTube comments")),
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")), "comments_text" => HTML.escape(I18n.translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")), "hide_replies_text" => HTML.escape(I18n.translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")), "show_replies_text" => HTML.escape(I18n.translate(locale, "Show replies")),
"preferences" => env.get("preferences").as(Preferences) "preferences" => env.get("preferences").as(Preferences)
}.to_pretty_json }.to_pretty_json
%> %>

View File

@ -27,7 +27,7 @@
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary" dir="auto" href="/feed/channel/<%= ucid %>"> <a class="pure-button pure-button-secondary" dir="auto" href="/feed/channel/<%= ucid %>">
<i class="icon ion-logo-rss"></i>&nbsp;<%= translate(locale, "generic_button_rss") %> <i class="icon ion-logo-rss"></i>&nbsp;<%= I18n.translate(locale, "generic_button_rss") %>
</a> </a>
</div> </div>
</div> </div>
@ -40,10 +40,10 @@
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<a href="<%= youtube_url %>"><%= translate(locale, "View channel on YouTube") %></a> <a href="<%= youtube_url %>"><%= I18n.translate(locale, "View channel on YouTube") %></a>
</div> </div>
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<a href="<%= redirect_url %>"><%= translate(locale, "Switch Invidious Instance") %></a> <a href="<%= redirect_url %>"><%= I18n.translate(locale, "Switch Invidious Instance") %></a>
</div> </div>
<%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, selected_tab) %> <%= Invidious::Frontend::ChannelPage.generate_tabs_links(locale, channel, selected_tab) %>
@ -53,9 +53,9 @@
<% sort_options.each do |sort| %> <% sort_options.each do |sort| %>
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<% if sort_by == sort %> <% if sort_by == sort %>
<b><%= translate(locale, sort) %></b> <b><%= I18n.translate(locale, sort) %></b>
<% else %> <% else %>
<a href="<%= relative_url %>?sort_by=<%= sort %>"><%= translate(locale, sort) %></a> <a href="<%= relative_url %>?sort_by=<%= sort %>"><%= I18n.translate(locale, sort) %></a>
<% end %> <% end %>
</div> </div>
<% end %> <% end %>

View File

@ -5,7 +5,7 @@
<% end %> <% end %>
<% feed_menu.each do |feed| %> <% feed_menu.each do |feed| %>
<a href="/feed/<%= feed.downcase %>" class="feed-menu-item pure-menu-heading"> <a href="/feed/<%= feed.downcase %>" class="feed-menu-item pure-menu-heading">
<%= translate(locale, feed) %> <%= I18n.translate(locale, feed) %>
</a> </a>
<% end %> <% end %>
</div> </div>

View File

@ -27,8 +27,8 @@
</div> </div>
<% if !item.channel_handle.nil? %><p class="channel-name" dir="auto"><%= item.channel_handle %></p><% end %> <% if !item.channel_handle.nil? %><p class="channel-name" dir="auto"><%= item.channel_handle %></p><% end %>
<p><%= translate_count(locale, "generic_subscribers_count", item.subscriber_count, NumberFormatting::Separator) %></p> <p><%= I18n.translate_count(locale, "generic_subscribers_count", item.subscriber_count, I18n::NumberFormatting::Separator) %></p>
<% if !item.auto_generated && item.channel_handle.nil? %><p><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p><% end %> <% if !item.auto_generated && item.channel_handle.nil? %><p><%= I18n.translate_count(locale, "generic_videos_count", item.video_count, I18n::NumberFormatting::Separator) %></p><% end %>
<h5><%= item.description_html %></h5> <h5><%= item.description_html %></h5>
<% when SearchHashtag %> <% when SearchHashtag %>
<% if !thin_mode %> <% if !thin_mode %>
@ -45,13 +45,13 @@
<div class="video-card-row"> <div class="video-card-row">
<%- if item.video_count != 0 -%> <%- if item.video_count != 0 -%>
<p><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p> <p><%= I18n.translate_count(locale, "generic_videos_count", item.video_count, I18n::NumberFormatting::Separator) %></p>
<%- end -%> <%- end -%>
</div> </div>
<div class="video-card-row"> <div class="video-card-row">
<%- if item.channel_count != 0 -%> <%- if item.channel_count != 0 -%>
<p><%= translate_count(locale, "generic_channels_count", item.channel_count, NumberFormatting::Separator) %></p> <p><%= I18n.translate_count(locale, "generic_channels_count", item.channel_count, I18n::NumberFormatting::Separator) %></p>
<%- end -%> <%- end -%>
</div> </div>
<% when SearchPlaylist, InvidiousPlaylist %> <% when SearchPlaylist, InvidiousPlaylist %>
@ -73,7 +73,7 @@
<%- end -%> <%- end -%>
<div class="bottom-right-overlay"> <div class="bottom-right-overlay">
<p class="length"><%= translate_count(locale, "generic_videos_count", item.video_count, NumberFormatting::Separator) %></p> <p class="length"><%= I18n.translate_count(locale, "generic_videos_count", item.video_count, I18n::NumberFormatting::Separator) %></p>
</div> </div>
</div> </div>
@ -101,11 +101,11 @@
<div class="error-card"> <div class="error-card">
<div class="explanation"> <div class="explanation">
<i class="icon ion-ios-alert"></i> <i class="icon ion-ios-alert"></i>
<h4><%=translate(locale, "timeline_parse_error_placeholder_heading")%></h4> <h4><%=I18n.translate(locale, "timeline_parse_error_placeholder_heading")%></h4>
<p><%=translate(locale, "timeline_parse_error_placeholder_message")%></p> <p><%=I18n.translate(locale, "timeline_parse_error_placeholder_message")%></p>
</div> </div>
<details> <details>
<summary class="pure-button pure-button-secondary"><%=translate(locale, "timeline_parse_error_show_technical_details")%></summary> <summary class="pure-button pure-button-secondary"><%=I18n.translate(locale, "timeline_parse_error_show_technical_details")%></summary>
<pre class="error-issue-template"><%=get_issue_template(env, item.parse_exception)[1]%></pre> <pre class="error-issue-template"><%=get_issue_template(env, item.parse_exception)[1]%></pre>
</details> </details>
</div> </div>
@ -168,7 +168,7 @@
<div class="bottom-right-overlay"> <div class="bottom-right-overlay">
<%- if item.responds_to?(:live_now) && item.live_now -%> <%- if item.responds_to?(:live_now) && item.live_now -%>
<p class="length" dir="auto"><i class="icon ion-ios-play-circle"></i>&nbsp;<%= translate(locale, "LIVE") %></p> <p class="length" dir="auto"><i class="icon ion-ios-play-circle"></i>&nbsp;<%= I18n.translate(locale, "LIVE") %></p>
<%- elsif item.length_seconds != 0 -%> <%- elsif item.length_seconds != 0 -%>
<p class="length"><%= recode_length_seconds(item.length_seconds) %></p> <p class="length"><%= recode_length_seconds(item.length_seconds) %></p>
<%- end -%> <%- end -%>
@ -200,15 +200,15 @@
<div class="video-card-row flexible"> <div class="video-card-row flexible">
<div class="flex-left"> <div class="flex-left">
<% if item.responds_to?(:premiere_timestamp) && item.premiere_timestamp.try &.> Time.utc %> <% if item.responds_to?(:premiere_timestamp) && item.premiere_timestamp.try &.> Time.utc %>
<p class="video-data" dir="auto"><%= translate(locale, "Premieres in `x`", recode_date((item.premiere_timestamp.as(Time) - Time.utc).ago, locale)) %></p> <p class="video-data" dir="auto"><%= I18n.translate(locale, "Premieres in `x`", recode_date((item.premiere_timestamp.as(Time) - Time.utc).ago, locale)) %></p>
<% elsif item.responds_to?(:published) && (Time.utc - item.published) > 1.minute %> <% elsif item.responds_to?(:published) && (Time.utc - item.published) > 1.minute %>
<p class="video-data" dir="auto"><%= translate(locale, "Shared `x` ago", recode_date(item.published, locale)) %></p> <p class="video-data" dir="auto"><%= I18n.translate(locale, "Shared `x` ago", recode_date(item.published, locale)) %></p>
<% end %> <% end %>
</div> </div>
<% if item.responds_to?(:views) && item.views %> <% if item.responds_to?(:views) && item.views %>
<div class="flex-right"> <div class="flex-right">
<p class="video-data" dir="auto"><%= translate_count(locale, "generic_views_count", item.views || 0, NumberFormatting::Short) %></p> <p class="video-data" dir="auto"><%= I18n.translate_count(locale, "generic_views_count", item.views || 0, I18n::NumberFormatting::Short) %></p>
</div> </div>
<% end %> <% end %>
</div> </div>

View File

@ -11,9 +11,9 @@
<script id="pagination-data" type="application/json"> <script id="pagination-data" type="application/json">
<%= <%=
{ {
"next_page" => translate(locale, "Next page"), "next_page" => I18n.translate(locale, "Next page"),
"prev_page" => translate(locale, "Previous page"), "prev_page" => I18n.translate(locale, "Previous page"),
"is_rtl" => locale_is_rtl?(locale) "is_rtl" => I18n.locale_is_rtl?(locale)
}.to_pretty_json }.to_pretty_json
%> %>
</script> </script>

View File

@ -2,11 +2,11 @@
<fieldset> <fieldset>
<input type="search" id="searchbox" autocorrect="off" <input type="search" id="searchbox" autocorrect="off"
autocapitalize="none" spellcheck="false" <% if autofocus %>autofocus<% end %> autocapitalize="none" spellcheck="false" <% if autofocus %>autofocus<% end %>
name="q" placeholder="<%= translate(locale, "search") %>" name="q" placeholder="<%= I18n.translate(locale, "search") %>"
title="<%= translate(locale, "search") %>" title="<%= I18n.translate(locale, "search") %>"
value="<%= env.get?("search").try {|x| HTML.escape(x.as(String)) } %>"> value="<%= env.get?("search").try {|x| HTML.escape(x.as(String)) } %>">
</fieldset> </fieldset>
<button type="submit" id="searchbutton" aria-label="<%= translate(locale, "search") %>"> <button type="submit" id="searchbutton" aria-label="<%= I18n.translate(locale, "search") %>">
<i class="icon ion-ios-search"></i> <i class="icon ion-ios-search"></i>
</button> </button>
</form> </form>

View File

@ -3,14 +3,14 @@
<form action="/subscription_ajax?action=remove_subscriptions&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post"> <form action="/subscription_ajax?action=remove_subscriptions&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<button data-type="unsubscribe" id="subscribe" class="pure-button pure-button-primary"> <button data-type="unsubscribe" id="subscribe" class="pure-button pure-button-primary">
<b><input style="all:unset" type="submit" value="<%= translate(locale, "Unsubscribe") %> | <%= sub_count_text %>"></b> <b><input style="all:unset" type="submit" value="<%= I18n.translate(locale, "Unsubscribe") %> | <%= sub_count_text %>"></b>
</button> </button>
</form> </form>
<% else %> <% else %>
<form action="/subscription_ajax?action=create_subscription_to_channel&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post"> <form action="/subscription_ajax?action=create_subscription_to_channel&c=<%= ucid %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<button data-type="subscribe" id="subscribe" class="pure-button pure-button-primary"> <button data-type="subscribe" id="subscribe" class="pure-button pure-button-primary">
<b><input style="all:unset" type="submit" value="<%= translate(locale, "Subscribe") %> | <%= sub_count_text %>"></b> <b><input style="all:unset" type="submit" value="<%= I18n.translate(locale, "Subscribe") %> | <%= sub_count_text %>"></b>
</button> </button>
</form> </form>
<% end %> <% end %>
@ -22,8 +22,8 @@
"author" => HTML.escape(author), "author" => HTML.escape(author),
"sub_count_text" => HTML.escape(sub_count_text), "sub_count_text" => HTML.escape(sub_count_text),
"csrf_token" => URI.encode_www_form(env.get?("csrf_token").try &.as(String) || ""), "csrf_token" => URI.encode_www_form(env.get?("csrf_token").try &.as(String) || ""),
"subscribe_text" => HTML.escape(translate(locale, "Subscribe")), "subscribe_text" => HTML.escape(I18n.translate(locale, "Subscribe")),
"unsubscribe_text" => HTML.escape(translate(locale, "Unsubscribe")) "unsubscribe_text" => HTML.escape(I18n.translate(locale, "Unsubscribe"))
}.to_pretty_json }.to_pretty_json
%> %>
</script> </script>
@ -31,6 +31,6 @@
<% else %> <% else %>
<a id="subscribe" class="pure-button pure-button-primary" <a id="subscribe" class="pure-button pure-button-primary"
href="/login?referer=<%= env.get("current_page") %>"> href="/login?referer=<%= env.get("current_page") %>">
<b><%= translate(locale, "Subscribe") %> | <%= sub_count_text %></b> <b><%= I18n.translate(locale, "Subscribe") %> | <%= sub_count_text %></b>
</a> </a>
<% end %> <% end %>

View File

@ -1,18 +1,18 @@
<div class="flex-right flexible"> <div class="flex-right flexible">
<div class="icon-buttons"> <div class="icon-buttons">
<a title="<%=translate(locale, "videoinfo_watch_on_youTube")%>" rel="noreferrer noopener" href="https://www.youtube.com/watch<%=endpoint_params%>"> <a title="<%=I18n.translate(locale, "videoinfo_watch_on_youTube")%>" rel="noreferrer noopener" href="https://www.youtube.com/watch<%=endpoint_params%>">
<i class="icon ion-logo-youtube"></i> <i class="icon ion-logo-youtube"></i>
</a> </a>
<a title="<%=translate(locale, "Audio mode")%>" href="/watch<%=endpoint_params%>&listen=1"> <a title="<%=I18n.translate(locale, "Audio mode")%>" href="/watch<%=endpoint_params%>&listen=1">
<i class="icon ion-md-headset"></i> <i class="icon ion-md-headset"></i>
</a> </a>
<% if env.get("preferences").as(Preferences).automatic_instance_redirect%> <% if env.get("preferences").as(Preferences).automatic_instance_redirect%>
<a title="<%=translate(locale, "Switch Invidious Instance")%>" href="/redirect?referer=%2Fwatch<%=URI.encode_www_form(endpoint_params)%>"> <a title="<%=I18n.translate(locale, "Switch Invidious Instance")%>" href="/redirect?referer=%2Fwatch<%=URI.encode_www_form(endpoint_params)%>">
<i class="icon ion-md-jet"></i> <i class="icon ion-md-jet"></i>
</a> </a>
<% else %> <% else %>
<a title="<%=translate(locale, "Switch Invidious Instance")%>" href="https://redirect.invidious.io/watch<%=endpoint_params%>"> <a title="<%=I18n.translate(locale, "Switch Invidious Instance")%>" href="https://redirect.invidious.io/watch<%=endpoint_params%>">
<i class="icon ion-md-jet"></i> <i class="icon ion-md-jet"></i>
</a> </a>
<% end %> <% end %>

View File

@ -1,5 +1,5 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Create playlist") %> - Invidious</title> <title><%= I18n.translate(locale, "Create playlist") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g"> <div class="pure-g">
@ -8,25 +8,25 @@
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/create_playlist?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/create_playlist?referer=<%= URI.encode_www_form(referer) %>" method="post">
<fieldset> <fieldset>
<legend><%= translate(locale, "Create playlist") %></legend> <legend><%= I18n.translate(locale, "Create playlist") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="title"><%= translate(locale, "Title") %> :</label> <label for="title"><%= I18n.translate(locale, "Title") %> :</label>
<input required name="title" type="text" placeholder="<%= translate(locale, "Title") %>"> <input required name="title" type="text" placeholder="<%= I18n.translate(locale, "Title") %>">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="privacy"><%= translate(locale, "Playlist privacy") %> :</label> <label for="privacy"><%= I18n.translate(locale, "Playlist privacy") %> :</label>
<select name="privacy" id="privacy"> <select name="privacy" id="privacy">
<% PlaylistPrivacy.names.each do |option| %> <% PlaylistPrivacy.names.each do |option| %>
<option value="<%= option %>" <% if option == "Public" %> selected <% end %>><%= translate(locale, option) %></option> <option value="<%= option %>" <% if option == "Public" %> selected <% end %>><%= I18n.translate(locale, option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-controls"> <div class="pure-controls">
<button type="submit" name="action" value="create_playlist" class="pure-button pure-button-primary"> <button type="submit" name="action" value="create_playlist" class="pure-button pure-button-primary">
<%= translate(locale, "Create playlist") %> <%= I18n.translate(locale, "Create playlist") %>
</button> </button>
</div> </div>

View File

@ -1,20 +1,20 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Delete playlist") %> - Invidious</title> <title><%= I18n.translate(locale, "Delete playlist") %> - Invidious</title>
<% end %> <% end %>
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/delete_playlist?list=<%= plid %>&referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/delete_playlist?list=<%= plid %>&referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "Delete playlist `x`?", %|"#{HTML.escape(playlist.title)}"|) %></legend> <legend><%= I18n.translate(locale, "Delete playlist `x`?", %|"#{HTML.escape(playlist.title)}"|) %></legend>
<div class="pure-g"> <div class="pure-g">
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<button type="submit" name="submit" value="delete_playlist" class="pure-button pure-button-primary"> <button type="submit" name="submit" value="delete_playlist" class="pure-button pure-button-primary">
<%= translate(locale, "Yes") %> <%= I18n.translate(locale, "Yes") %>
</button> </button>
</div> </div>
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<a class="pure-button" href="/playlist?list=<%= plid %>"> <a class="pure-button" href="/playlist?list=<%= plid %>">
<%= translate(locale, "No") %> <%= I18n.translate(locale, "No") %>
</a> </a>
</div> </div>
</div> </div>

View File

@ -10,17 +10,17 @@
<div class="flex-right button-container"> <div class="flex-right button-container">
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/playlist?list=<%= plid %>">
<i class="icon ion-md-close"></i>&nbsp;<%= translate(locale, "generic_button_cancel") %> <i class="icon ion-md-close"></i>&nbsp;<%= I18n.translate(locale, "generic_button_cancel") %>
</a> </a>
</div> </div>
<div class="pure-u"> <div class="pure-u">
<button class="pure-button pure-button-secondary low-profile" dir="auto" type="submit"> <button class="pure-button pure-button-secondary low-profile" dir="auto" type="submit">
<i class="icon ion-md-save"></i>&nbsp;<%= translate(locale, "generic_button_save") %> <i class="icon ion-md-save"></i>&nbsp;<%= I18n.translate(locale, "generic_button_save") %>
</button> </button>
</div> </div>
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>">
<i class="icon ion-md-trash"></i>&nbsp;<%= translate(locale, "generic_button_delete") %> <i class="icon ion-md-trash"></i>&nbsp;<%= I18n.translate(locale, "generic_button_delete") %>
</a> </a>
</div> </div>
</div> </div>
@ -36,11 +36,11 @@
<div class="pure-u-1-1"> <div class="pure-u-1-1">
<b> <b>
<%= HTML.escape(playlist.author) %> | <%= HTML.escape(playlist.author) %> |
<%= translate_count(locale, "generic_videos_count", playlist.video_count) %> | <%= I18n.translate_count(locale, "generic_videos_count", playlist.video_count) %> |
</b> </b>
<select name="privacy"> <select name="privacy">
<%- {"Public", "Unlisted", "Private"}.each do |option| -%> <%- {"Public", "Unlisted", "Private"}.each do |option| -%>
<option value="<%= option %>" <% if option == playlist.privacy.to_s %>selected<% end %>><%= translate(locale, option) %></option> <option value="<%= option %>" <% if option == playlist.privacy.to_s %>selected<% end %>><%= I18n.translate(locale, option) %></option>
<%- end -%> <%- end -%>
</select> </select>
</div> </div>

View File

@ -1,19 +1,19 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "History") %> - Invidious</title> <title><%= I18n.translate(locale, "History") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3><%= translate_count(locale, "generic_videos_count", user.watched.size, NumberFormatting::HtmlSpan) %></h3> <h3><%= I18n.translate_count(locale, "generic_videos_count", user.watched.size, I18n::NumberFormatting::HtmlSpan) %></h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:center"> <h3 style="text-align:center">
<a href="/feed/subscriptions"><%= translate_count(locale, "generic_subscriptions_count", user.subscriptions.size, NumberFormatting::HtmlSpan) %></a> <a href="/feed/subscriptions"><%= I18n.translate_count(locale, "generic_subscriptions_count", user.subscriptions.size, I18n::NumberFormatting::HtmlSpan) %></a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:right"> <h3 style="text-align:right">
<a href="/clear_watch_history"><%= translate(locale, "Clear watch history") %></a> <a href="/clear_watch_history"><%= I18n.translate(locale, "Clear watch history") %></a>
</h3> </h3>
</div> </div>
</div> </div>

View File

@ -1,22 +1,22 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Playlists") %> - Invidious</title> <title><%= I18n.translate(locale, "Playlists") %> - Invidious</title>
<% end %> <% end %>
<%= rendered "components/feed_menu" %> <%= rendered "components/feed_menu" %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3><%= translate(locale, "user_created_playlists", %(<span id="count">#{items_created.size}</span>)) %></h3> <h3><%= I18n.translate(locale, "user_created_playlists", %(<span id="count">#{items_created.size}</span>)) %></h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:center"> <h3 style="text-align:center">
<a href="/create_playlist?referer=<%= URI.encode_www_form("/feed/playlists") %>"><%= translate(locale, "Create playlist") %></a> <a href="/create_playlist?referer=<%= URI.encode_www_form("/feed/playlists") %>"><%= I18n.translate(locale, "Create playlist") %></a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:right"> <h3 style="text-align:right">
<a href="/data_control?referer=<%= URI.encode_www_form("/feed/playlists") %>"> <a href="/data_control?referer=<%= URI.encode_www_form("/feed/playlists") %>">
<%= translate(locale, "Import/export") %> <%= I18n.translate(locale, "Import/export") %>
</a> </a>
</h3> </h3>
</div> </div>
@ -30,7 +30,7 @@
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1"> <div class="pure-u-1">
<h3><%= translate(locale, "user_saved_playlists", %(<span id="count">#{items_saved.size}</span>)) %></h3> <h3><%= I18n.translate(locale, "user_saved_playlists", %(<span id="count">#{items_saved.size}</span>)) %></h3>
</div> </div>
</div> </div>

View File

@ -1,8 +1,8 @@
<% content_for "header" do %> <% content_for "header" do %>
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> <meta name="description" content="<%= I18n.translate(locale, "An alternative front-end to YouTube") %>">
<title> <title>
<% if env.get("preferences").as(Preferences).default_home != "Popular" %> <% if env.get("preferences").as(Preferences).default_home != "Popular" %>
<%= translate(locale, "Popular") %> - Invidious <%= I18n.translate(locale, "Popular") %> - Invidious
<% else %> <% else %>
Invidious Invidious
<% end %> <% end %>

View File

@ -1,5 +1,5 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Subscriptions") %> - Invidious</title> <title><%= I18n.translate(locale, "Subscriptions") %> - Invidious</title>
<link rel="alternate" type="application/rss+xml" title="RSS" href="/feed/private?token=<%= token %>" /> <link rel="alternate" type="application/rss+xml" title="RSS" href="/feed/private?token=<%= token %>" />
<% end %> <% end %>
@ -8,12 +8,12 @@
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3> <h3>
<a href="/subscription_manager"><%= translate(locale, "Manage subscriptions") %></a> <a href="/subscription_manager"><%= I18n.translate(locale, "Manage subscriptions") %></a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:center"> <h3 style="text-align:center">
<a href="/feed/history"><%= translate(locale, "Watch history") %></a> <a href="/feed/history"><%= I18n.translate(locale, "Watch history") %></a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
@ -26,7 +26,7 @@
<% if CONFIG.enable_user_notifications %> <% if CONFIG.enable_user_notifications %>
<center> <center>
<%= translate_count(locale, "subscriptions_unseen_notifs_count", notifications.size) %> <%= I18n.translate_count(locale, "subscriptions_unseen_notifs_count", notifications.size) %>
</center> </center>
<% if !notifications.empty? %> <% if !notifications.empty? %>

View File

@ -1,8 +1,8 @@
<% content_for "header" do %> <% content_for "header" do %>
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> <meta name="description" content="<%= I18n.translate(locale, "An alternative front-end to YouTube") %>">
<title> <title>
<% if env.get("preferences").as(Preferences).default_home != "Trending" %> <% if env.get("preferences").as(Preferences).default_home != "Trending" %>
<%= translate(locale, "Trending") %> - Invidious <%= I18n.translate(locale, "Trending") %> - Invidious
<% else %> <% else %>
Invidious Invidious
<% end %> <% end %>
@ -15,7 +15,7 @@
<div style="align-self:flex-end" class="pure-u-2-3"> <div style="align-self:flex-end" class="pure-u-2-3">
<% if plid %> <% if plid %>
<a href="/playlist?list=<%= plid %>"> <a href="/playlist?list=<%= plid %>">
<%= translate(locale, "View as playlist") %> <%= I18n.translate(locale, "View as playlist") %>
</a> </a>
<% end %> <% end %>
</div> </div>
@ -24,10 +24,10 @@
<% {"Livestreams", "Gaming"}.each do |option| %> <% {"Livestreams", "Gaming"}.each do |option| %>
<div class="pure-u-1 pure-md-1-3"> <div class="pure-u-1 pure-md-1-3">
<% if trending_type == option %> <% if trending_type == option %>
<b><%= translate(locale, option) %></b> <b><%= I18n.translate(locale, option) %></b>
<% else %> <% else %>
<a href="/feed/trending?type=<%= option %>&region=<%= region %>"> <a href="/feed/trending?type=<%= option %>&region=<%= region %>">
<%= translate(locale, option) %> <%= I18n.translate(locale, option) %>
</a> </a>
<% end %> <% end %>
</div> </div>

View File

@ -7,7 +7,7 @@
</head> </head>
<body> <body>
<h1><%= translate(locale, "JavaScript license information") %></h1> <h1><%= I18n.translate(locale, "JavaScript license information") %></h1>
<table id="jslicense-labels1"> <table id="jslicense-labels1">
<tr> <tr>
<td> <td>
@ -19,7 +19,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/iv-org/videojs-quality-selector"><%= translate(locale, "source") %></a> <a href="https://github.com/iv-org/videojs-quality-selector"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -33,7 +33,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/mpetazzoni/sse.js"><%= translate(locale, "source") %></a> <a href="https://github.com/mpetazzoni/sse.js"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -47,7 +47,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/videojs/videojs-contrib-quality-levels"><%= translate(locale, "source") %></a> <a href="https://github.com/videojs/videojs-contrib-quality-levels"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -61,7 +61,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/jfujita/videojs-http-source-selector"><%= translate(locale, "source") %></a> <a href="https://github.com/jfujita/videojs-http-source-selector"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -75,7 +75,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/mister-ben/videojs-mobile-ui"><%= translate(locale, "source") %></a> <a href="https://github.com/mister-ben/videojs-mobile-ui"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -89,7 +89,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/spchuang/videojs-markers"><%= translate(locale, "source") %></a> <a href="https://github.com/spchuang/videojs-markers"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -103,7 +103,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/brightcove/videojs-overlay"><%= translate(locale, "source") %></a> <a href="https://github.com/brightcove/videojs-overlay"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -117,7 +117,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/mkhazov/videojs-share"><%= translate(locale, "source") %></a> <a href="https://github.com/mkhazov/videojs-share"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -131,7 +131,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/chrisboustead/videojs-vtt-thumbnails"><%= translate(locale, "source") %></a> <a href="https://github.com/chrisboustead/videojs-vtt-thumbnails"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -145,7 +145,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/afrmtbl/videojs-youtube-annotations"><%= translate(locale, "source") %></a> <a href="https://github.com/afrmtbl/videojs-youtube-annotations"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -159,7 +159,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/videojs/videojs-vr"><%= translate(locale, "source") %></a> <a href="https://github.com/videojs/videojs-vr"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>
@ -173,7 +173,7 @@
</td> </td>
<td> <td>
<a href="https://github.com/videojs/video.js"><%= translate(locale, "source") %></a> <a href="https://github.com/videojs/video.js"><%= I18n.translate(locale, "source") %></a>
</td> </td>
</tr> </tr>

View File

@ -1,5 +1,5 @@
<% content_for "header" do %> <% content_for "header" do %>
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> <meta name="description" content="<%= I18n.translate(locale, "An alternative front-end to YouTube") %>">
<title> <title>
Invidious Invidious
</title> </title>

View File

@ -13,28 +13,28 @@
<%- if playlist.is_a?(InvidiousPlaylist) && playlist.author == user.try &.email -%> <%- if playlist.is_a?(InvidiousPlaylist) && playlist.author == user.try &.email -%>
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/add_playlist_items?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/add_playlist_items?list=<%= plid %>">
<i class="icon ion-md-add"></i>&nbsp;<%= translate(locale, "playlist_button_add_items") %> <i class="icon ion-md-add"></i>&nbsp;<%= I18n.translate(locale, "playlist_button_add_items") %>
</a> </a>
</div> </div>
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/edit_playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/edit_playlist?list=<%= plid %>">
<i class="icon ion-md-create"></i>&nbsp;<%= translate(locale, "generic_button_edit") %> <i class="icon ion-md-create"></i>&nbsp;<%= I18n.translate(locale, "generic_button_edit") %>
</a> </a>
</div> </div>
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>">
<i class="icon ion-md-trash"></i>&nbsp;<%= translate(locale, "generic_button_delete") %> <i class="icon ion-md-trash"></i>&nbsp;<%= I18n.translate(locale, "generic_button_delete") %>
</a> </a>
</div> </div>
<%- else -%> <%- else -%>
<div class="pure-u"> <div class="pure-u">
<%- if IV::Database::Playlists.exists?(playlist.id) -%> <%- if IV::Database::Playlists.exists?(playlist.id) -%>
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/subscribe_playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/subscribe_playlist?list=<%= plid %>">
<i class="icon ion-md-add"></i>&nbsp;<%= translate(locale, "Subscribe") %> <i class="icon ion-md-add"></i>&nbsp;<%= I18n.translate(locale, "Subscribe") %>
</a> </a>
<%- else -%> <%- else -%>
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/delete_playlist?list=<%= plid %>">
<i class="icon ion-md-trash"></i>&nbsp;<%= translate(locale, "Unsubscribe") %> <i class="icon ion-md-trash"></i>&nbsp;<%= I18n.translate(locale, "Unsubscribe") %>
</a> </a>
<%- end -%> <%- end -%>
</div> </div>
@ -42,7 +42,7 @@
<div class="pure-u"> <div class="pure-u">
<a class="pure-button pure-button-secondary low-profile" dir="auto" href="/feed/playlist/<%= plid %>"> <a class="pure-button pure-button-secondary low-profile" dir="auto" href="/feed/playlist/<%= plid %>">
<i class="icon ion-logo-rss"></i>&nbsp;<%= translate(locale, "generic_button_rss") %> <i class="icon ion-logo-rss"></i>&nbsp;<%= I18n.translate(locale, "generic_button_rss") %>
</a> </a>
</div> </div>
</div> </div>
@ -57,15 +57,15 @@
<% else %> <% else %>
<%= author %> | <%= author %> |
<% end %> <% end %>
<%= translate_count(locale, "generic_videos_count", playlist.video_count) %> | <%= I18n.translate_count(locale, "generic_videos_count", playlist.video_count) %> |
<%= translate(locale, "Updated `x` ago", recode_date(playlist.updated, locale)) %> | <%= I18n.translate(locale, "Updated `x` ago", recode_date(playlist.updated, locale)) %> |
<% case playlist.as(InvidiousPlaylist).privacy when %> <% case playlist.as(InvidiousPlaylist).privacy when %>
<% when PlaylistPrivacy::Public %> <% when PlaylistPrivacy::Public %>
<i class="icon ion-md-globe"></i> <%= translate(locale, "Public") %> <i class="icon ion-md-globe"></i> <%= I18n.translate(locale, "Public") %>
<% when PlaylistPrivacy::Unlisted %> <% when PlaylistPrivacy::Unlisted %>
<i class="icon ion-ios-unlock"></i> <%= translate(locale, "Unlisted") %> <i class="icon ion-ios-unlock"></i> <%= I18n.translate(locale, "Unlisted") %>
<% when PlaylistPrivacy::Private %> <% when PlaylistPrivacy::Private %>
<i class="icon ion-ios-lock"></i> <%= translate(locale, "Private") %> <i class="icon ion-ios-lock"></i> <%= I18n.translate(locale, "Private") %>
<% end %> <% end %>
</b> </b>
<% else %> <% else %>
@ -76,25 +76,25 @@
<% subtitle = playlist.subtitle || "" %> <% subtitle = playlist.subtitle || "" %>
<span><%= HTML.escape(subtitle[0..subtitle.rindex(" • ") || subtitle.size]) %></span> | <span><%= HTML.escape(subtitle[0..subtitle.rindex(" • ") || subtitle.size]) %></span> |
<% end %> <% end %>
<%= translate_count(locale, "generic_videos_count", playlist.video_count) %> | <%= I18n.translate_count(locale, "generic_videos_count", playlist.video_count) %> |
<%= translate(locale, "Updated `x` ago", recode_date(playlist.updated, locale)) %> <%= I18n.translate(locale, "Updated `x` ago", recode_date(playlist.updated, locale)) %>
</b> </b>
<% end %> <% end %>
<% if !playlist.is_a? InvidiousPlaylist %> <% if !playlist.is_a? InvidiousPlaylist %>
<div class="pure-u-2-3"> <div class="pure-u-2-3">
<a rel="noreferrer noopener" href="https://www.youtube.com/playlist?list=<%= playlist.id %>"> <a rel="noreferrer noopener" href="https://www.youtube.com/playlist?list=<%= playlist.id %>">
<%= translate(locale, "View playlist on YouTube") %> <%= I18n.translate(locale, "View playlist on YouTube") %>
</a> </a>
<span> | </span> <span> | </span>
<% if env.get("preferences").as(Preferences).automatic_instance_redirect%> <% if env.get("preferences").as(Preferences).automatic_instance_redirect%>
<a href="/redirect?referer=<%= env.get?("current_page") %>"> <a href="/redirect?referer=<%= env.get?("current_page") %>">
<%= translate(locale, "Switch Invidious Instance") %> <%= I18n.translate(locale, "Switch Invidious Instance") %>
</a> </a>
<% else %> <% else %>
<a href="https://redirect.invidious.io/playlist?list=<%= playlist.id %>"> <a href="https://redirect.invidious.io/playlist?list=<%= playlist.id %>">
<%= translate(locale, "Switch Invidious Instance") %> <%= I18n.translate(locale, "Switch Invidious Instance") %>
</a> </a>
<% end %> <% end %>
</div> </div>

View File

@ -18,7 +18,7 @@
<% else %> <% else %>
<noscript> <noscript>
<a href="/post/<%= id %>?ucid=<%= ucid %>&nojs=1"> <a href="/post/<%= id %>?ucid=<%= ucid %>&nojs=1">
<%= translate(locale, "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.") %> <%= I18n.translate(locale, "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.") %>
</a> </a>
</noscript> </noscript>
<% end %> <% end %>
@ -29,12 +29,12 @@
<%= <%=
{ {
"id" => id, "id" => id,
"youtube_comments_text" => HTML.escape(translate(locale, "View YouTube comments")), "youtube_comments_text" => HTML.escape(I18n.translate(locale, "View YouTube comments")),
"reddit_comments_text" => "", "reddit_comments_text" => "",
"reddit_permalink_text" => "", "reddit_permalink_text" => "",
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")), "comments_text" => HTML.escape(I18n.translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")), "hide_replies_text" => HTML.escape(I18n.translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")), "show_replies_text" => HTML.escape(I18n.translate(locale, "Show replies")),
"params" => { "params" => {
"comments": ["youtube"] "comments": ["youtube"]
}, },

View File

@ -11,9 +11,9 @@
<%- if items.empty? -%> <%- if items.empty? -%>
<div class="h-box no-results-error"> <div class="h-box no-results-error">
<div> <div>
<%= translate(locale, "search_message_no_results") %><br/><br/> <%= I18n.translate(locale, "search_message_no_results") %><br/><br/>
<%= translate(locale, "search_message_change_filters_or_query") %><br/><br/> <%= I18n.translate(locale, "search_message_change_filters_or_query") %><br/><br/>
<%= translate(locale, "search_message_use_another_instance", redirect_url) %> <%= I18n.translate(locale, "search_message_use_another_instance", redirect_url) %>
</div> </div>
</div> </div>
<%- else -%> <%- else -%>

View File

@ -1,7 +1,7 @@
<% content_for "header" do %> <% content_for "header" do %>
<meta name="description" content="<%= translate(locale, "An alternative front-end to YouTube") %>"> <meta name="description" content="<%= I18n.translate(locale, "An alternative front-end to YouTube") %>">
<title> <title>
Invidious - <%= translate(locale, "search") %> Invidious - <%= I18n.translate(locale, "search") %>
</title> </title>
<link rel="stylesheet" href="/css/empty.css?v=<%= ASSET_COMMIT %>"> <link rel="stylesheet" href="/css/empty.css?v=<%= ASSET_COMMIT %>">
<% end %> <% end %>

View File

@ -43,7 +43,7 @@
<div class="pure-u-1 pure-u-md-8-24 user-field"> <div class="pure-u-1 pure-u-md-8-24 user-field">
<% if env.get? "user" %> <% if env.get? "user" %>
<div class="pure-u-1-4"> <div class="pure-u-1-4">
<a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading" title="<%= translate(locale, "toggle_theme") %>"> <a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading" title="<%= I18n.translate(locale, "toggle_theme") %>">
<% if dark_mode == "dark" %> <% if dark_mode == "dark" %>
<i class="icon ion-ios-sunny"></i> <i class="icon ion-ios-sunny"></i>
<% else %> <% else %>
@ -52,7 +52,7 @@
</a> </a>
</div> </div>
<div class="pure-u-1-4"> <div class="pure-u-1-4">
<a id="notification_ticker" title="<%= translate(locale, "Subscriptions") %>" href="/feed/subscriptions" class="pure-menu-heading"> <a id="notification_ticker" title="<%= I18n.translate(locale, "Subscriptions") %>" href="/feed/subscriptions" class="pure-menu-heading">
<% notification_count = env.get("user").as(Invidious::User).notifications.size %> <% notification_count = env.get("user").as(Invidious::User).notifications.size %>
<% if CONFIG.enable_user_notifications && notification_count > 0 %> <% if CONFIG.enable_user_notifications && notification_count > 0 %>
<span id="notification_count"><%= notification_count %></span> <i class="icon ion-ios-notifications"></i> <span id="notification_count"><%= notification_count %></span> <i class="icon ion-ios-notifications"></i>
@ -62,7 +62,7 @@
</a> </a>
</div> </div>
<div class="pure-u-1-4"> <div class="pure-u-1-4">
<a title="<%= translate(locale, "Preferences") %>" href="/preferences?referer=<%= env.get?("current_page") %>" class="pure-menu-heading"> <a title="<%= I18n.translate(locale, "Preferences") %>" href="/preferences?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
<i class="icon ion-ios-cog"></i> <i class="icon ion-ios-cog"></i>
</a> </a>
</div> </div>
@ -75,13 +75,13 @@
<form action="/signout?referer=<%= env.get?("current_page") %>" method="post"> <form action="/signout?referer=<%= env.get?("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<a class="pure-menu-heading" href="#"> <a class="pure-menu-heading" href="#">
<input style="all:unset" type="submit" value="<%= translate(locale, "Log out") %>"> <input style="all:unset" type="submit" value="<%= I18n.translate(locale, "Log out") %>">
</a> </a>
</form> </form>
</div> </div>
<% else %> <% else %>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading" title="<%= translate(locale, "toggle_theme") %>"> <a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading" title="<%= I18n.translate(locale, "toggle_theme") %>">
<% if dark_mode == "dark" %> <% if dark_mode == "dark" %>
<i class="icon ion-ios-sunny"></i> <i class="icon ion-ios-sunny"></i>
<% else %> <% else %>
@ -90,14 +90,14 @@
</a> </a>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<a title="<%= translate(locale, "Preferences") %>" href="/preferences?referer=<%= env.get?("current_page") %>" class="pure-menu-heading"> <a title="<%= I18n.translate(locale, "Preferences") %>" href="/preferences?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
<i class="icon ion-ios-cog"></i> <i class="icon ion-ios-cog"></i>
</a> </a>
</div> </div>
<% if CONFIG.login_enabled %> <% if CONFIG.login_enabled %>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<a href="/login?referer=<%= env.get?("current_page") %>" class="pure-menu-heading"> <a href="/login?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
<%= translate(locale, "Log in") %> <%= I18n.translate(locale, "Log in") %>
</a> </a>
</div> </div>
<% end %> <% end %>
@ -119,39 +119,39 @@
<span> <span>
<i class="icon ion-logo-github"></i> <i class="icon ion-logo-github"></i>
<% if CONFIG.modified_source_code_url %> <% if CONFIG.modified_source_code_url %>
<a href="https://github.com/iv-org/invidious"><%= translate(locale, "footer_original_source_code") %></a>&nbsp;/ <a href="https://github.com/iv-org/invidious"><%= I18n.translate(locale, "footer_original_source_code") %></a>&nbsp;/
<a href="<%= CONFIG.modified_source_code_url %>"><%= translate(locale, "footer_modfied_source_code") %></a> <a href="<%= CONFIG.modified_source_code_url %>"><%= I18n.translate(locale, "footer_modfied_source_code") %></a>
<% else %> <% else %>
<a href="https://github.com/iv-org/invidious"><%= translate(locale, "footer_source_code") %></a> <a href="https://github.com/iv-org/invidious"><%= I18n.translate(locale, "footer_source_code") %></a>
<% end %> <% end %>
</span> </span>
<span> <span>
<i class="icon ion-ios-paper"></i> <i class="icon ion-ios-paper"></i>
<a href="https://github.com/iv-org/documentation"><%= translate(locale, "footer_documentation") %></a> <a href="https://github.com/iv-org/documentation"><%= I18n.translate(locale, "footer_documentation") %></a>
</span> </span>
</div> </div>
<div class="pure-u-1 pure-u-md-1-3"> <div class="pure-u-1 pure-u-md-1-3">
<span> <span>
<a href="https://github.com/iv-org/invidious/blob/master/LICENSE"><%= translate(locale, "Released under the AGPLv3 on Github.") %></a> <a href="https://github.com/iv-org/invidious/blob/master/LICENSE"><%= I18n.translate(locale, "Released under the AGPLv3 on Github.") %></a>
</span> </span>
<span> <span>
<i class="icon ion-logo-javascript"></i> <i class="icon ion-logo-javascript"></i>
<a rel="jslicense" href="/licenses"><%= translate(locale, "View JavaScript license information.") %></a> <a rel="jslicense" href="/licenses"><%= I18n.translate(locale, "View JavaScript license information.") %></a>
</span> </span>
<span> <span>
<i class="icon ion-ios-paper"></i> <i class="icon ion-ios-paper"></i>
<a href="/privacy"><%= translate(locale, "View privacy policy.") %></a> <a href="/privacy"><%= I18n.translate(locale, "View privacy policy.") %></a>
</span> </span>
</div> </div>
<div class="pure-u-1 pure-u-md-1-3"> <div class="pure-u-1 pure-u-md-1-3">
<span> <span>
<i class="icon ion-ios-wallet"></i> <i class="icon ion-ios-wallet"></i>
<a href="https://invidious.io/donate/"><%= translate(locale, "footer_donate_page") %></a> <a href="https://invidious.io/donate/"><%= I18n.translate(locale, "footer_donate_page") %></a>
</span> </span>
<span> <span>
<%= translate(locale, "Current version: ") %> <%= I18n.translate(locale, "Current version: ") %>
<% if CONFIG.modified_source_code_url %> <% if CONFIG.modified_source_code_url %>
<a href="<%= CONFIG.modified_source_code_url %>/commit/<%= CURRENT_COMMIT %>"><%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %></a> <a href="<%= CONFIG.modified_source_code_url %>/commit/<%= CURRENT_COMMIT %>"><%= CURRENT_VERSION %>-<%= CURRENT_COMMIT %></a>
<% else %> <% else %>
@ -181,8 +181,8 @@
<script id="notification_data" type="application/json"> <script id="notification_data" type="application/json">
<%= <%=
{ {
"upload_text" => HTML.escape(translate(locale, "`x` uploaded a video")), "upload_text" => HTML.escape(I18n.translate(locale, "`x` uploaded a video")),
"live_upload_text" => HTML.escape(translate(locale, "`x` is live")) "live_upload_text" => HTML.escape(I18n.translate(locale, "`x` is live"))
}.to_pretty_json }.to_pretty_json
%> %>
</script> </script>

View File

@ -1,22 +1,22 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Token") %> - Invidious</title> <title><%= I18n.translate(locale, "Token") %> - Invidious</title>
<% end %> <% end %>
<% if env.get? "access_token" %> <% if env.get? "access_token" %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3> <h3>
<%= translate(locale, "Token") %> <%= I18n.translate(locale, "Token") %>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:center"> <h3 style="text-align:center">
<a href="/token_manager"><%= translate(locale, "Token manager") %></a> <a href="/token_manager"><%= I18n.translate(locale, "Token manager") %></a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:right"> <h3 style="text-align:right">
<a href="/preferences"><%= translate(locale, "Preferences") %></a> <a href="/preferences"><%= I18n.translate(locale, "Preferences") %></a>
</h3> </h3>
</div> </div>
</div> </div>
@ -30,9 +30,9 @@
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/authorize_token" method="post"> <form class="pure-form pure-form-aligned" action="/authorize_token" method="post">
<% if callback_url %> <% if callback_url %>
<legend><%= translate(locale, "Authorize token for `x`?", "#{callback_url.scheme}://#{callback_url.host}") %></legend> <legend><%= I18n.translate(locale, "Authorize token for `x`?", "#{callback_url.scheme}://#{callback_url.host}") %></legend>
<% else %> <% else %>
<legend><%= translate(locale, "Authorize token?") %></legend> <legend><%= I18n.translate(locale, "Authorize token?") %></legend>
<% end %> <% end %>
<div class="pure-g"> <div class="pure-g">
@ -48,7 +48,7 @@
<div class="pure-g"> <div class="pure-g">
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<button type="submit" name="submit" value="clear_watch_history" class="pure-button pure-button-primary"> <button type="submit" name="submit" value="clear_watch_history" class="pure-button pure-button-primary">
<%= translate(locale, "Yes") %> <%= I18n.translate(locale, "Yes") %>
</button> </button>
</div> </div>
<div class="pure-u-1-2"> <div class="pure-u-1-2">
@ -57,7 +57,7 @@
<% else %> <% else %>
<a class="pure-button" href="/"> <a class="pure-button" href="/">
<% end %> <% end %>
<%= translate(locale, "No") %> <%= I18n.translate(locale, "No") %>
</a> </a>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Change password") %> - Invidious</title> <title><%= I18n.translate(locale, "Change password") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g"> <div class="pure-g">
@ -7,20 +7,20 @@
<div class="pure-u-1 pure-u-lg-3-5"> <div class="pure-u-1 pure-u-lg-3-5">
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/change_password?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/change_password?referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "Change password") %></legend> <legend><%= I18n.translate(locale, "Change password") %></legend>
<fieldset> <fieldset>
<label for="password"><%= translate(locale, "Password") %> :</label> <label for="password"><%= I18n.translate(locale, "Password") %> :</label>
<input required class="pure-input-1" name="password" type="password" placeholder="<%= translate(locale, "Password") %>"> <input required class="pure-input-1" name="password" type="password" placeholder="<%= I18n.translate(locale, "Password") %>">
<label for="new_password[0]"><%= translate(locale, "New password") %> :</label> <label for="new_password[0]"><%= I18n.translate(locale, "New password") %> :</label>
<input required class="pure-input-1" name="new_password[0]" type="password" placeholder="<%= translate(locale, "New password") %>"> <input required class="pure-input-1" name="new_password[0]" type="password" placeholder="<%= I18n.translate(locale, "New password") %>">
<label for="new_password[1]"><%= translate(locale, "New password") %> :</label> <label for="new_password[1]"><%= I18n.translate(locale, "New password") %> :</label>
<input required class="pure-input-1" name="new_password[1]" type="password" placeholder="<%= translate(locale, "New password") %>"> <input required class="pure-input-1" name="new_password[1]" type="password" placeholder="<%= I18n.translate(locale, "New password") %>">
<button type="submit" name="action" value="change_password" class="pure-button pure-button-primary"> <button type="submit" name="action" value="change_password" class="pure-button pure-button-primary">
<%= translate(locale, "Change password") %> <%= I18n.translate(locale, "Change password") %>
</button> </button>
<input type="hidden" name="csrf_token" value="<%= HTML.escape(csrf_token) %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(csrf_token) %>">

View File

@ -1,20 +1,20 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Clear watch history") %> - Invidious</title> <title><%= I18n.translate(locale, "Clear watch history") %> - Invidious</title>
<% end %> <% end %>
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/clear_watch_history?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/clear_watch_history?referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "Clear watch history?") %></legend> <legend><%= I18n.translate(locale, "Clear watch history?") %></legend>
<div class="pure-g"> <div class="pure-g">
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<button type="submit" name="submit" value="clear_watch_history" class="pure-button pure-button-primary"> <button type="submit" name="submit" value="clear_watch_history" class="pure-button pure-button-primary">
<%= translate(locale, "Yes") %> <%= I18n.translate(locale, "Yes") %>
</button> </button>
</div> </div>
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<a class="pure-button" href="<%= URI.encode_www_form(referer) %>"> <a class="pure-button" href="<%= URI.encode_www_form(referer) %>">
<%= translate(locale, "No") %> <%= I18n.translate(locale, "No") %>
</a> </a>
</div> </div>
</div> </div>

View File

@ -1,67 +1,67 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Import and Export Data") %> - Invidious</title> <title><%= I18n.translate(locale, "Import and Export Data") %> - Invidious</title>
<% end %> <% end %>
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" enctype="multipart/form-data" action="/data_control?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" enctype="multipart/form-data" action="/data_control?referer=<%= URI.encode_www_form(referer) %>" method="post">
<fieldset> <fieldset>
<legend><%= translate(locale, "Import") %></legend> <legend><%= I18n.translate(locale, "Import") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_invidious"><%= translate(locale, "Import Invidious data") %></label> <label for="import_invidious"><%= I18n.translate(locale, "Import Invidious data") %></label>
<input type="file" id="import_invidious" name="import_invidious"> <input type="file" id="import_invidious" name="import_invidious">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_youtube"> <label for="import_youtube">
<a rel="noopener noreferrer" target="_blank" href="https://github.com/iv-org/documentation/blob/master/docs/export-youtube-subscriptions.md"> <a rel="noopener noreferrer" target="_blank" href="https://github.com/iv-org/documentation/blob/master/docs/export-youtube-subscriptions.md">
<%= translate(locale, "Import YouTube subscriptions") %> <%= I18n.translate(locale, "Import YouTube subscriptions") %>
</a> </a>
</label> </label>
<input type="file" id="import_youtube" name="import_youtube"> <input type="file" id="import_youtube" name="import_youtube">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_youtube_pl"><%= translate(locale, "Import YouTube playlist (.csv)") %></label> <label for="import_youtube_pl"><%= I18n.translate(locale, "Import YouTube playlist (.csv)") %></label>
<input type="file" id="import_youtube_pl" name="import_youtube_pl"> <input type="file" id="import_youtube_pl" name="import_youtube_pl">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_youtube_wh"><%= translate(locale, "Import YouTube watch history (.json)") %></label> <label for="import_youtube_wh"><%= I18n.translate(locale, "Import YouTube watch history (.json)") %></label>
<input type="file" id="import_youtube_wh" name="import_youtube_wh"> <input type="file" id="import_youtube_wh" name="import_youtube_wh">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_freetube"><%= translate(locale, "Import FreeTube subscriptions (.db)") %></label> <label for="import_freetube"><%= I18n.translate(locale, "Import FreeTube subscriptions (.db)") %></label>
<input type="file" id="import_freetube" name="import_freetube"> <input type="file" id="import_freetube" name="import_freetube">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_newpipe_subscriptions"><%= translate(locale, "Import NewPipe subscriptions (.json)") %></label> <label for="import_newpipe_subscriptions"><%= I18n.translate(locale, "Import NewPipe subscriptions (.json)") %></label>
<input type="file" id="import_newpipe_subscriptions" name="import_newpipe_subscriptions"> <input type="file" id="import_newpipe_subscriptions" name="import_newpipe_subscriptions">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="import_newpipe"><%= translate(locale, "Import NewPipe data (.zip)") %></label> <label for="import_newpipe"><%= I18n.translate(locale, "Import NewPipe data (.zip)") %></label>
<input type="file" id="import_newpipe" name="import_newpipe"> <input type="file" id="import_newpipe" name="import_newpipe">
</div> </div>
<div class="pure-controls"> <div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary"><%= translate(locale, "Import") %></button> <button type="submit" class="pure-button pure-button-primary"><%= I18n.translate(locale, "Import") %></button>
</div> </div>
<legend><%= translate(locale, "Export") %></legend> <legend><%= I18n.translate(locale, "Export") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/subscription_manager?action_takeout=1"><%= translate(locale, "Export subscriptions as OPML") %></a> <a href="/subscription_manager?action_takeout=1"><%= I18n.translate(locale, "Export subscriptions as OPML") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/subscription_manager?action_takeout=1&format=newpipe"><%= translate(locale, "Export subscriptions as OPML (for NewPipe & FreeTube)") %></a> <a href="/subscription_manager?action_takeout=1&format=newpipe"><%= I18n.translate(locale, "Export subscriptions as OPML (for NewPipe & FreeTube)") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/subscription_manager?action_takeout=1&format=json"><%= translate(locale, "Export data as JSON") %></a> <a href="/subscription_manager?action_takeout=1&format=json"><%= I18n.translate(locale, "Export data as JSON") %></a>
</div> </div>
</fieldset> </fieldset>
</form> </form>

View File

@ -1,20 +1,20 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Delete account") %> - Invidious</title> <title><%= I18n.translate(locale, "Delete account") %> - Invidious</title>
<% end %> <% end %>
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/delete_account?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/delete_account?referer=<%= URI.encode_www_form(referer) %>" method="post">
<legend><%= translate(locale, "Delete account?") %></legend> <legend><%= I18n.translate(locale, "Delete account?") %></legend>
<div class="pure-g"> <div class="pure-g">
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<button type="submit" name="submit" value="delete_account" class="pure-button pure-button-primary"> <button type="submit" name="submit" value="delete_account" class="pure-button pure-button-primary">
<%= translate(locale, "Yes") %> <%= I18n.translate(locale, "Yes") %>
</button> </button>
</div> </div>
<div class="pure-u-1-2"> <div class="pure-u-1-2">
<a class="pure-button" href="<%= URI.encode_www_form(referer) %>"> <a class="pure-button" href="<%= URI.encode_www_form(referer) %>">
<%= translate(locale, "No") %> <%= I18n.translate(locale, "No") %>
</a> </a>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Log in") %> - Invidious</title> <title><%= I18n.translate(locale, "Log in") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g"> <div class="pure-g">
@ -13,15 +13,15 @@
<% if email %> <% if email %>
<input name="email" type="hidden" value="<%= HTML.escape(email) %>"> <input name="email" type="hidden" value="<%= HTML.escape(email) %>">
<% else %> <% else %>
<label for="email"><%= translate(locale, "User ID") %> :</label> <label for="email"><%= I18n.translate(locale, "User ID") %> :</label>
<input required class="pure-input-1" name="email" type="text" placeholder="<%= translate(locale, "User ID") %>"> <input required class="pure-input-1" name="email" type="text" placeholder="<%= I18n.translate(locale, "User ID") %>">
<% end %> <% end %>
<% if password %> <% if password %>
<input name="password" type="hidden" value="<%= HTML.escape(password) %>"> <input name="password" type="hidden" value="<%= HTML.escape(password) %>">
<% else %> <% else %>
<label for="password"><%= translate(locale, "Password") %> :</label> <label for="password"><%= I18n.translate(locale, "Password") %> :</label>
<input required class="pure-input-1" name="password" type="password" placeholder="<%= translate(locale, "Password") %>"> <input required class="pure-input-1" name="password" type="password" placeholder="<%= I18n.translate(locale, "Password") %>">
<% end %> <% end %>
<% if captcha %> <% if captcha %>
@ -30,15 +30,15 @@
<% captcha[:tokens].each_with_index do |token, i| %> <% captcha[:tokens].each_with_index do |token, i| %>
<input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>"> <input type="hidden" name="token[<%= i %>]" value="<%= HTML.escape(token) %>">
<% end %> <% end %>
<label for="answer"><%= translate(locale, "Time (h:mm:ss):") %></label> <label for="answer"><%= I18n.translate(locale, "Time (h:mm:ss):") %></label>
<input type="text" name="answer" type="text" placeholder="h:mm:ss"> <input type="text" name="answer" type="text" placeholder="h:mm:ss">
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary"> <button type="submit" name="action" value="signin" class="pure-button pure-button-primary">
<%= translate(locale, "Register") %> <%= I18n.translate(locale, "Register") %>
</button> </button>
<% else %> <% else %>
<button type="submit" name="action" value="signin" class="pure-button pure-button-primary"> <button type="submit" name="action" value="signin" class="pure-button pure-button-primary">
<%= translate(locale, "Sign In") %>/<%= translate(locale, "Register") %> <%= I18n.translate(locale, "Sign In") %>/<%= I18n.translate(locale, "Register") %>
</button> </button>
<% end %> <% end %>
</fieldset> </fieldset>

View File

@ -1,49 +1,49 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Preferences") %> - Invidious</title> <title><%= I18n.translate(locale, "Preferences") %> - Invidious</title>
<% end %> <% end %>
<div class="h-box"> <div class="h-box">
<form class="pure-form pure-form-aligned" action="/preferences?referer=<%= URI.encode_www_form(referer) %>" method="post"> <form class="pure-form pure-form-aligned" action="/preferences?referer=<%= URI.encode_www_form(referer) %>" method="post">
<fieldset> <fieldset>
<legend><%= translate(locale, "preferences_category_player") %></legend> <legend><%= I18n.translate(locale, "preferences_category_player") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="video_loop"><%= translate(locale, "preferences_video_loop_label") %></label> <label for="video_loop"><%= I18n.translate(locale, "preferences_video_loop_label") %></label>
<input name="video_loop" id="video_loop" type="checkbox" <% if preferences.video_loop %>checked<% end %>> <input name="video_loop" id="video_loop" type="checkbox" <% if preferences.video_loop %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="preload"><%= translate(locale, "preferences_preload_label") %></label> <label for="preload"><%= I18n.translate(locale, "preferences_preload_label") %></label>
<input name="preload" id="preload" type="checkbox" <% if preferences.preload %>checked<% end %>> <input name="preload" id="preload" type="checkbox" <% if preferences.preload %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="autoplay"><%= translate(locale, "preferences_autoplay_label") %></label> <label for="autoplay"><%= I18n.translate(locale, "preferences_autoplay_label") %></label>
<input name="autoplay" id="autoplay" type="checkbox" <% if preferences.autoplay %>checked<% end %>> <input name="autoplay" id="autoplay" type="checkbox" <% if preferences.autoplay %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="continue"><%= translate(locale, "preferences_continue_label") %></label> <label for="continue"><%= I18n.translate(locale, "preferences_continue_label") %></label>
<input name="continue" id="continue" type="checkbox" <% if preferences.continue %>checked<% end %>> <input name="continue" id="continue" type="checkbox" <% if preferences.continue %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="continue_autoplay"><%= translate(locale, "preferences_continue_autoplay_label") %></label> <label for="continue_autoplay"><%= I18n.translate(locale, "preferences_continue_autoplay_label") %></label>
<input name="continue_autoplay" id="continue_autoplay" type="checkbox" <% if preferences.continue_autoplay %>checked<% end %>> <input name="continue_autoplay" id="continue_autoplay" type="checkbox" <% if preferences.continue_autoplay %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="local"><%= translate(locale, "preferences_local_label") %></label> <label for="local"><%= I18n.translate(locale, "preferences_local_label") %></label>
<input name="local" id="local" type="checkbox" <% if preferences.local && !CONFIG.disabled?("local") %>checked<% end %> <% if CONFIG.disabled?("local") %>disabled<% end %>> <input name="local" id="local" type="checkbox" <% if preferences.local && !CONFIG.disabled?("local") %>checked<% end %> <% if CONFIG.disabled?("local") %>disabled<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="listen"><%= translate(locale, "preferences_listen_label") %></label> <label for="listen"><%= I18n.translate(locale, "preferences_listen_label") %></label>
<input name="listen" id="listen" type="checkbox" <% if preferences.listen %>checked<% end %>> <input name="listen" id="listen" type="checkbox" <% if preferences.listen %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="speed"><%= translate(locale, "preferences_speed_label") %></label> <label for="speed"><%= I18n.translate(locale, "preferences_speed_label") %></label>
<select name="speed" id="speed"> <select name="speed" id="speed">
<% {2.0, 1.75, 1.5, 1.25, 1.0, 0.75, 0.5, 0.25}.each do |option| %> <% {2.0, 1.75, 1.5, 1.25, 1.0, 0.75, 0.5, 0.25}.each do |option| %>
<option <% if preferences.speed == option %> selected <% end %>><%= option %></option> <option <% if preferences.speed == option %> selected <% end %>><%= option %></option>
@ -52,11 +52,11 @@
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="quality"><%= translate(locale, "preferences_quality_label") %></label> <label for="quality"><%= I18n.translate(locale, "preferences_quality_label") %></label>
<select name="quality" id="quality"> <select name="quality" id="quality">
<% {"dash", "hd720", "medium", "small"}.each do |option| %> <% {"dash", "hd720", "medium", "small"}.each do |option| %>
<% if !(option == "dash" && CONFIG.disabled?("dash")) %> <% if !(option == "dash" && CONFIG.disabled?("dash")) %>
<option value="<%= option %>" <% if preferences.quality == option %> selected <% end %>><%= translate(locale, "preferences_quality_option_" + option) %></option> <option value="<%= option %>" <% if preferences.quality == option %> selected <% end %>><%= I18n.translate(locale, "preferences_quality_option_" + option) %></option>
<% end %> <% end %>
<% end %> <% end %>
</select> </select>
@ -64,74 +64,74 @@
<% if !CONFIG.disabled?("dash") %> <% if !CONFIG.disabled?("dash") %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="quality_dash"><%= translate(locale, "preferences_quality_dash_label") %></label> <label for="quality_dash"><%= I18n.translate(locale, "preferences_quality_dash_label") %></label>
<select name="quality_dash" id="quality_dash"> <select name="quality_dash" id="quality_dash">
<% {"auto", "best", "4320p", "2160p", "1440p", "1080p", "720p", "480p", "360p", "240p", "144p", "worst"}.each do |option| %> <% {"auto", "best", "4320p", "2160p", "1440p", "1080p", "720p", "480p", "360p", "240p", "144p", "worst"}.each do |option| %>
<option value="<%= option %>" <% if preferences.quality_dash == option %> selected <% end %>><%= translate(locale, "preferences_quality_dash_option_" + option) %></option> <option value="<%= option %>" <% if preferences.quality_dash == option %> selected <% end %>><%= I18n.translate(locale, "preferences_quality_dash_option_" + option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<% end %> <% end %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="volume"><%= translate(locale, "preferences_volume_label") %></label> <label for="volume"><%= I18n.translate(locale, "preferences_volume_label") %></label>
<input name="volume" id="volume" data-onrange="update_volume_value" type="range" min="0" max="100" step="5" value="<%= preferences.volume %>"> <input name="volume" id="volume" data-onrange="update_volume_value" type="range" min="0" max="100" step="5" value="<%= preferences.volume %>">
<span class="pure-form-message-inline" id="volume-value"><%= preferences.volume %></span> <span class="pure-form-message-inline" id="volume-value"><%= preferences.volume %></span>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="comments[0]"><%= translate(locale, "preferences_comments_label") %></label> <label for="comments[0]"><%= I18n.translate(locale, "preferences_comments_label") %></label>
<% preferences.comments.each_with_index do |comments, index| %> <% preferences.comments.each_with_index do |comments, index| %>
<select name="comments[<%= index %>]" id="comments[<%= index %>]"> <select name="comments[<%= index %>]" id="comments[<%= index %>]">
<% {"", "youtube", "reddit"}.each do |option| %> <% {"", "youtube", "reddit"}.each do |option| %>
<option value="<%= option %>" <% if preferences.comments[index] == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> <option value="<%= option %>" <% if preferences.comments[index] == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "none" : option) %></option>
<% end %> <% end %>
</select> </select>
<% end %> <% end %>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="captions[0]"><%= translate(locale, "preferences_captions_label") %></label> <label for="captions[0]"><%= I18n.translate(locale, "preferences_captions_label") %></label>
<% preferences.captions.each_with_index do |caption, index| %> <% preferences.captions.each_with_index do |caption, index| %>
<select class="pure-u-1-6" name="captions[<%= index %>]" id="captions[<%= index %>]"> <select class="pure-u-1-6" name="captions[<%= index %>]" id="captions[<%= index %>]">
<% Invidious::Videos::Captions::LANGUAGES.each do |option| %> <% Invidious::Videos::Captions::LANGUAGES.each do |option| %>
<option value="<%= option %>" <% if preferences.captions[index] == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> <option value="<%= option %>" <% if preferences.captions[index] == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "none" : option) %></option>
<% end %> <% end %>
</select> </select>
<% end %> <% end %>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="related_videos"><%= translate(locale, "preferences_related_videos_label") %></label> <label for="related_videos"><%= I18n.translate(locale, "preferences_related_videos_label") %></label>
<input name="related_videos" id="related_videos" type="checkbox" <% if preferences.related_videos %>checked<% end %>> <input name="related_videos" id="related_videos" type="checkbox" <% if preferences.related_videos %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="annotations"><%= translate(locale, "preferences_annotations_label") %></label> <label for="annotations"><%= I18n.translate(locale, "preferences_annotations_label") %></label>
<input name="annotations" id="annotations" type="checkbox" <% if preferences.annotations %>checked<% end %>> <input name="annotations" id="annotations" type="checkbox" <% if preferences.annotations %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="extend_desc"><%= translate(locale, "preferences_extend_desc_label") %></label> <label for="extend_desc"><%= I18n.translate(locale, "preferences_extend_desc_label") %></label>
<input name="extend_desc" id="extend_desc" type="checkbox" <% if preferences.extend_desc %>checked<% end %>> <input name="extend_desc" id="extend_desc" type="checkbox" <% if preferences.extend_desc %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="vr_mode"><%= translate(locale, "preferences_vr_mode_label") %></label> <label for="vr_mode"><%= I18n.translate(locale, "preferences_vr_mode_label") %></label>
<input name="vr_mode" id="vr_mode" type="checkbox" <% if preferences.vr_mode %>checked<% end %>> <input name="vr_mode" id="vr_mode" type="checkbox" <% if preferences.vr_mode %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="save_player_pos"><%= translate(locale, "preferences_save_player_pos_label") %></label> <label for="save_player_pos"><%= I18n.translate(locale, "preferences_save_player_pos_label") %></label>
<input name="save_player_pos" id="save_player_pos" type="checkbox" <% if preferences.save_player_pos %>checked<% end %>> <input name="save_player_pos" id="save_player_pos" type="checkbox" <% if preferences.save_player_pos %>checked<% end %>>
</div> </div>
<% if user = env.get?("user").try &.as(User) %> <% if user = env.get?("user").try &.as(User) %>
<% playlists = Invidious::Database::Playlists.select_user_created_playlists(user.email) %> <% playlists = Invidious::Database::Playlists.select_user_created_playlists(user.email) %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="default_playlist"><%= translate(locale, "preferences_default_playlist") %></label> <label for="default_playlist"><%= I18n.translate(locale, "preferences_default_playlist") %></label>
<select name="default_playlist" id="default_playlist"> <select name="default_playlist" id="default_playlist">
<option value=""><%= translate(locale, "preferences_default_playlist_none") %></option> <option value=""><%= I18n.translate(locale, "preferences_default_playlist_none") %></option>
<% playlists.each do |plid, playlist_title| %> <% playlists.each do |plid, playlist_title| %>
<option value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option> <option value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option>
<% end %> <% end %>
@ -139,46 +139,46 @@
</div> </div>
<% end %> <% end %>
<legend><%= translate(locale, "preferences_category_visual") %></legend> <legend><%= I18n.translate(locale, "preferences_category_visual") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="locale"><%= translate(locale, "preferences_locale_label") %></label> <label for="locale"><%= I18n.translate(locale, "preferences_locale_label") %></label>
<select name="locale" id="locale"> <select name="locale" id="locale">
<% LOCALES_LIST.each do |iso_name, full_name| %> <% I18n::LOCALES_LIST.each do |iso_name, full_name| %>
<option value="<%= iso_name %>" <% if preferences.locale == iso_name %> selected <% end %>><%= HTML.escape(full_name) %></option> <option value="<%= iso_name %>" <% if preferences.locale == iso_name %> selected <% end %>><%= HTML.escape(full_name) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="region"><%= translate(locale, "preferences_region_label") %></label> <label for="region"><%= I18n.translate(locale, "preferences_region_label") %></label>
<select name="region" id="region"> <select name="region" id="region">
<% CONTENT_REGIONS.each do |option| %> <% I18n::CONTENT_REGIONS.each do |option| %>
<option value="<%= option %>" <% if preferences.region == option %> selected <% end %>><%= option %></option> <option value="<%= option %>" <% if preferences.region == option %> selected <% end %>><%= option %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="player_style"><%= translate(locale, "preferences_player_style_label") %></label> <label for="player_style"><%= I18n.translate(locale, "preferences_player_style_label") %></label>
<select name="player_style" id="player_style"> <select name="player_style" id="player_style">
<% {"invidious", "youtube"}.each do |option| %> <% {"invidious", "youtube"}.each do |option| %>
<option value="<%= option %>" <% if preferences.player_style == option %> selected <% end %>><%= translate(locale, option) %></option> <option value="<%= option %>" <% if preferences.player_style == option %> selected <% end %>><%= I18n.translate(locale, option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="dark_mode"><%= translate(locale, "preferences_dark_mode_label") %></label> <label for="dark_mode"><%= I18n.translate(locale, "preferences_dark_mode_label") %></label>
<select name="dark_mode" id="dark_mode"> <select name="dark_mode" id="dark_mode">
<% {"", "light", "dark"}.each do |option| %> <% {"", "light", "dark"}.each do |option| %>
<option value="<%= option %>" <% if preferences.dark_mode == option %> selected <% end %>><%= translate(locale, option.blank? ? "auto" : option) %></option> <option value="<%= option %>" <% if preferences.dark_mode == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "auto" : option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="thin_mode"><%= translate(locale, "preferences_thin_mode_label") %></label> <label for="thin_mode"><%= I18n.translate(locale, "preferences_thin_mode_label") %></label>
<input name="thin_mode" id="thin_mode" type="checkbox" <% if preferences.thin_mode %>checked<% end %>> <input name="thin_mode" id="thin_mode" type="checkbox" <% if preferences.thin_mode %>checked<% end %>>
</div> </div>
@ -189,187 +189,187 @@
<% end %> <% end %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="default_home"><%= translate(locale, "preferences_default_home_label") %></label> <label for="default_home"><%= I18n.translate(locale, "preferences_default_home_label") %></label>
<select name="default_home" id="default_home"> <select name="default_home" id="default_home">
<% feed_options.each do |option| %> <% feed_options.each do |option| %>
<option value="<%= option %>" <% if preferences.default_home == option %> selected <% end %>><%= translate(locale, option.blank? ? "Search" : option) %></option> <option value="<%= option %>" <% if preferences.default_home == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "Search" : option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="feed_menu"><%= translate(locale, "preferences_feed_menu_label") %></label> <label for="feed_menu"><%= I18n.translate(locale, "preferences_feed_menu_label") %></label>
<% (feed_options.size - 1).times do |index| %> <% (feed_options.size - 1).times do |index| %>
<select name="feed_menu[<%= index %>]" id="feed_menu[<%= index %>]"> <select name="feed_menu[<%= index %>]" id="feed_menu[<%= index %>]">
<% feed_options.each do |option| %> <% feed_options.each do |option| %>
<option value="<%= option %>" <% if preferences.feed_menu[index]? == option %> selected <% end %>><%= translate(locale, option.blank? ? "Search" : option) %></option> <option value="<%= option %>" <% if preferences.feed_menu[index]? == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "Search" : option) %></option>
<% end %> <% end %>
</select> </select>
<% end %> <% end %>
</div> </div>
<% if env.get? "user" %> <% if env.get? "user" %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="show_nick"><%= translate(locale, "preferences_show_nick_label") %></label> <label for="show_nick"><%= I18n.translate(locale, "preferences_show_nick_label") %></label>
<input name="show_nick" id="show_nick" type="checkbox" <% if preferences.show_nick %>checked<% end %>> <input name="show_nick" id="show_nick" type="checkbox" <% if preferences.show_nick %>checked<% end %>>
</div> </div>
<% end %> <% end %>
<legend><%= translate(locale, "preferences_category_misc") %></legend> <legend><%= I18n.translate(locale, "preferences_category_misc") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="automatic_instance_redirect"><%= translate(locale, "preferences_automatic_instance_redirect_label") %></label> <label for="automatic_instance_redirect"><%= I18n.translate(locale, "preferences_automatic_instance_redirect_label") %></label>
<input name="automatic_instance_redirect" id="automatic_instance_redirect" type="checkbox" <% if preferences.automatic_instance_redirect %>checked<% end %>> <input name="automatic_instance_redirect" id="automatic_instance_redirect" type="checkbox" <% if preferences.automatic_instance_redirect %>checked<% end %>>
</div> </div>
<% if env.get? "user" %> <% if env.get? "user" %>
<legend><%= translate(locale, "preferences_category_subscription") %></legend> <legend><%= I18n.translate(locale, "preferences_category_subscription") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="watch_history"><%= translate(locale, "preferences_watch_history_label") %></label> <label for="watch_history"><%= I18n.translate(locale, "preferences_watch_history_label") %></label>
<input name="watch_history" id="watch_history" type="checkbox" <% if preferences.watch_history %>checked<% end %>> <input name="watch_history" id="watch_history" type="checkbox" <% if preferences.watch_history %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="annotations_subscribed"><%= translate(locale, "preferences_annotations_subscribed_label") %></label> <label for="annotations_subscribed"><%= I18n.translate(locale, "preferences_annotations_subscribed_label") %></label>
<input name="annotations_subscribed" id="annotations_subscribed" type="checkbox" <% if preferences.annotations_subscribed %>checked<% end %>> <input name="annotations_subscribed" id="annotations_subscribed" type="checkbox" <% if preferences.annotations_subscribed %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="max_results"><%= translate(locale, "preferences_max_results_label") %></label> <label for="max_results"><%= I18n.translate(locale, "preferences_max_results_label") %></label>
<input name="max_results" id="max_results" type="number" value="<%= preferences.max_results %>"> <input name="max_results" id="max_results" type="number" value="<%= preferences.max_results %>">
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="sort"><%= translate(locale, "preferences_sort_label") %></label> <label for="sort"><%= I18n.translate(locale, "preferences_sort_label") %></label>
<select name="sort" id="sort"> <select name="sort" id="sort">
<% {"published", "published - reverse", "alphabetically", "alphabetically - reverse", "channel name", "channel name - reverse"}.each do |option| %> <% {"published", "published - reverse", "alphabetically", "alphabetically - reverse", "channel name", "channel name - reverse"}.each do |option| %>
<option value="<%= option %>" <% if preferences.sort == option %> selected <% end %>><%= translate(locale, option) %></option> <option value="<%= option %>" <% if preferences.sort == option %> selected <% end %>><%= I18n.translate(locale, option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<% if preferences.unseen_only %> <% if preferences.unseen_only %>
<label for="latest_only"><%= translate(locale, "Only show latest unwatched video from channel: ") %></label> <label for="latest_only"><%= I18n.translate(locale, "Only show latest unwatched video from channel: ") %></label>
<% else %> <% else %>
<label for="latest_only"><%= translate(locale, "Only show latest video from channel: ") %></label> <label for="latest_only"><%= I18n.translate(locale, "Only show latest video from channel: ") %></label>
<% end %> <% end %>
<input name="latest_only" id="latest_only" type="checkbox" <% if preferences.latest_only %>checked<% end %>> <input name="latest_only" id="latest_only" type="checkbox" <% if preferences.latest_only %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="unseen_only"><%= translate(locale, "preferences_unseen_only_label") %></label> <label for="unseen_only"><%= I18n.translate(locale, "preferences_unseen_only_label") %></label>
<input name="unseen_only" id="unseen_only" type="checkbox" <% if preferences.unseen_only %>checked<% end %>> <input name="unseen_only" id="unseen_only" type="checkbox" <% if preferences.unseen_only %>checked<% end %>>
</div> </div>
<% if CONFIG.enable_user_notifications %> <% if CONFIG.enable_user_notifications %>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="notifications_only"><%= translate(locale, "preferences_notifications_only_label") %></label> <label for="notifications_only"><%= I18n.translate(locale, "preferences_notifications_only_label") %></label>
<input name="notifications_only" id="notifications_only" type="checkbox" <% if preferences.notifications_only %>checked<% end %>> <input name="notifications_only" id="notifications_only" type="checkbox" <% if preferences.notifications_only %>checked<% end %>>
</div> </div>
<% # Web notifications are only supported over HTTPS %> <% # Web notifications are only supported over HTTPS %>
<% if Kemal.config.ssl || CONFIG.https_only %> <% if Kemal.config.ssl || CONFIG.https_only %>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="#" data-onclick="notification_requestPermission"><%= translate(locale, "Enable web notifications") %></a> <a href="#" data-onclick="notification_requestPermission"><%= I18n.translate(locale, "Enable web notifications") %></a>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
<% end %> <% end %>
<% if env.get?("user") && CONFIG.admins.includes? env.get?("user").as(Invidious::User).email %> <% if env.get?("user") && CONFIG.admins.includes? env.get?("user").as(Invidious::User).email %>
<legend><%= translate(locale, "preferences_category_admin") %></legend> <legend><%= I18n.translate(locale, "preferences_category_admin") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="admin_default_home"><%= translate(locale, "preferences_default_home_label") %></label> <label for="admin_default_home"><%= I18n.translate(locale, "preferences_default_home_label") %></label>
<select name="admin_default_home" id="admin_default_home"> <select name="admin_default_home" id="admin_default_home">
<% feed_options.each do |option| %> <% feed_options.each do |option| %>
<option value="<%= option %>" <% if CONFIG.default_user_preferences.default_home == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> <option value="<%= option %>" <% if CONFIG.default_user_preferences.default_home == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "none" : option) %></option>
<% end %> <% end %>
</select> </select>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="admin_feed_menu"><%= translate(locale, "preferences_feed_menu_label") %></label> <label for="admin_feed_menu"><%= I18n.translate(locale, "preferences_feed_menu_label") %></label>
<% (feed_options.size - 1).times do |index| %> <% (feed_options.size - 1).times do |index| %>
<select name="admin_feed_menu[<%= index %>]" id="admin_feed_menu[<%= index %>]"> <select name="admin_feed_menu[<%= index %>]" id="admin_feed_menu[<%= index %>]">
<% feed_options.each do |option| %> <% feed_options.each do |option| %>
<option value="<%= option %>" <% if CONFIG.default_user_preferences.feed_menu[index]? == option %> selected <% end %>><%= translate(locale, option.blank? ? "none" : option) %></option> <option value="<%= option %>" <% if CONFIG.default_user_preferences.feed_menu[index]? == option %> selected <% end %>><%= I18n.translate(locale, option.blank? ? "none" : option) %></option>
<% end %> <% end %>
</select> </select>
<% end %> <% end %>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="popular_enabled"><%= translate(locale, "Popular enabled: ") %></label> <label for="popular_enabled"><%= I18n.translate(locale, "Popular enabled: ") %></label>
<input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.popular_enabled %>checked<% end %>> <input name="popular_enabled" id="popular_enabled" type="checkbox" <% if CONFIG.popular_enabled %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="captcha_enabled"><%= translate(locale, "CAPTCHA enabled: ") %></label> <label for="captcha_enabled"><%= I18n.translate(locale, "CAPTCHA enabled: ") %></label>
<input name="captcha_enabled" id="captcha_enabled" type="checkbox" <% if CONFIG.captcha_enabled %>checked<% end %>> <input name="captcha_enabled" id="captcha_enabled" type="checkbox" <% if CONFIG.captcha_enabled %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="login_enabled"><%= translate(locale, "Login enabled: ") %></label> <label for="login_enabled"><%= I18n.translate(locale, "Login enabled: ") %></label>
<input name="login_enabled" id="login_enabled" type="checkbox" <% if CONFIG.login_enabled %>checked<% end %>> <input name="login_enabled" id="login_enabled" type="checkbox" <% if CONFIG.login_enabled %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="registration_enabled"><%= translate(locale, "Registration enabled: ") %></label> <label for="registration_enabled"><%= I18n.translate(locale, "Registration enabled: ") %></label>
<input name="registration_enabled" id="registration_enabled" type="checkbox" <% if CONFIG.registration_enabled %>checked<% end %>> <input name="registration_enabled" id="registration_enabled" type="checkbox" <% if CONFIG.registration_enabled %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="statistics_enabled"><%= translate(locale, "Report statistics: ") %></label> <label for="statistics_enabled"><%= I18n.translate(locale, "Report statistics: ") %></label>
<input name="statistics_enabled" id="statistics_enabled" type="checkbox" <% if CONFIG.statistics_enabled %>checked<% end %>> <input name="statistics_enabled" id="statistics_enabled" type="checkbox" <% if CONFIG.statistics_enabled %>checked<% end %>>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="modified_source_code_url"><%= translate(locale, "adminprefs_modified_source_code_url_label") %></label> <label for="modified_source_code_url"><%= I18n.translate(locale, "adminprefs_modified_source_code_url_label") %></label>
<input name="modified_source_code_url" id="modified_source_code_url" type="url" value="<%= CONFIG.modified_source_code_url %>"> <input name="modified_source_code_url" id="modified_source_code_url" type="url" value="<%= CONFIG.modified_source_code_url %>">
</div> </div>
<% end %> <% end %>
<% if env.get? "user" %> <% if env.get? "user" %>
<legend><%= translate(locale, "preferences_category_data") %></legend> <legend><%= I18n.translate(locale, "preferences_category_data") %></legend>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/clear_watch_history?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Clear watch history") %></a> <a href="/clear_watch_history?referer=<%= URI.encode_www_form(referer) %>"><%= I18n.translate(locale, "Clear watch history") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/change_password?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Change password") %></a> <a href="/change_password?referer=<%= URI.encode_www_form(referer) %>"><%= I18n.translate(locale, "Change password") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/data_control?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Import/export data") %></a> <a href="/data_control?referer=<%= URI.encode_www_form(referer) %>"><%= I18n.translate(locale, "Import/export data") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/subscription_manager"><%= translate(locale, "Manage subscriptions") %></a> <a href="/subscription_manager"><%= I18n.translate(locale, "Manage subscriptions") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/token_manager"><%= translate(locale, "Manage tokens") %></a> <a href="/token_manager"><%= I18n.translate(locale, "Manage tokens") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/feed/playlists"><%= translate(locale, "View all playlists") %></a> <a href="/feed/playlists"><%= I18n.translate(locale, "View all playlists") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/feed/history"><%= translate(locale, "Watch history") %></a> <a href="/feed/history"><%= I18n.translate(locale, "Watch history") %></a>
</div> </div>
<div class="pure-control-group"> <div class="pure-control-group">
<a href="/delete_account?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Delete account") %></a> <a href="/delete_account?referer=<%= URI.encode_www_form(referer) %>"><%= I18n.translate(locale, "Delete account") %></a>
</div> </div>
<% end %> <% end %>
<div class="pure-controls"> <div class="pure-controls">
<button type="submit" class="pure-button pure-button-primary"><%= translate(locale, "Save preferences") %></button> <button type="submit" class="pure-button pure-button-primary"><%= I18n.translate(locale, "Save preferences") %></button>
</div> </div>
</fieldset> </fieldset>
</form> </form>

View File

@ -1,26 +1,26 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Subscription manager") %> - Invidious</title> <title><%= I18n.translate(locale, "Subscription manager") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3> <h3>
<a href="/feed/subscriptions"> <a href="/feed/subscriptions">
<%= translate_count(locale, "generic_subscriptions_count", subscriptions.size, NumberFormatting::HtmlSpan) %> <%= I18n.translate_count(locale, "generic_subscriptions_count", subscriptions.size, I18n::NumberFormatting::HtmlSpan) %>
</a> </a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:center"> <h3 style="text-align:center">
<a href="/feed/history"> <a href="/feed/history">
<%= translate(locale, "Watch history") %> <%= I18n.translate(locale, "Watch history") %>
</a> </a>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3 style="text-align:right"> <h3 style="text-align:right">
<a href="/data_control?referer=<%= URI.encode_www_form(referer) %>"> <a href="/data_control?referer=<%= URI.encode_www_form(referer) %>">
<%= translate(locale, "Import/export") %> <%= I18n.translate(locale, "Import/export") %>
</a> </a>
</h3> </h3>
</div> </div>
@ -39,7 +39,7 @@
<h3 style="padding-right:0.5em"> <h3 style="padding-right:0.5em">
<form data-onsubmit="return_false" action="/subscription_ajax?action=remove_subscriptions&c=<%= channel.id %>&referer=<%= env.get("current_page") %>" method="post"> <form data-onsubmit="return_false" action="/subscription_ajax?action=remove_subscriptions&c=<%= channel.id %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<input style="all:unset" type="submit" data-onclick="remove_subscription" data-ucid="<%= channel.id %>" value="<%= translate(locale, "unsubscribe") %>"> <input style="all:unset" type="submit" data-onclick="remove_subscription" data-ucid="<%= channel.id %>" value="<%= I18n.translate(locale, "unsubscribe") %>">
</form> </form>
</h3> </h3>
</div> </div>

View File

@ -1,17 +1,17 @@
<% content_for "header" do %> <% content_for "header" do %>
<title><%= translate(locale, "Token manager") %> - Invidious</title> <title><%= I18n.translate(locale, "Token manager") %> - Invidious</title>
<% end %> <% end %>
<div class="pure-g h-box"> <div class="pure-g h-box">
<div class="pure-u-1-3"> <div class="pure-u-1-3">
<h3> <h3>
<%= translate_count(locale, "tokens_count", tokens.size, NumberFormatting::HtmlSpan) %> <%= I18n.translate_count(locale, "tokens_count", tokens.size, I18n::NumberFormatting::HtmlSpan) %>
</h3> </h3>
</div> </div>
<div class="pure-u-1-3"></div> <div class="pure-u-1-3"></div>
<div class="pure-u-1-3" style="text-align:right"> <div class="pure-u-1-3" style="text-align:right">
<h3> <h3>
<a href="/preferences?referer=<%= URI.encode_www_form(referer) %>"><%= translate(locale, "Preferences") %></a> <a href="/preferences?referer=<%= URI.encode_www_form(referer) %>"><%= I18n.translate(locale, "Preferences") %></a>
</h3> </h3>
</div> </div>
</div> </div>
@ -25,13 +25,13 @@
</h4> </h4>
</div> </div>
<div class="pure-u-1-5" style="text-align:center"> <div class="pure-u-1-5" style="text-align:center">
<h4><%= translate(locale, "`x` ago", recode_date(token[:issued], locale)) %></h4> <h4><%= I18n.translate(locale, "`x` ago", recode_date(token[:issued], locale)) %></h4>
</div> </div>
<div class="pure-u-1-5" style="text-align:right"> <div class="pure-u-1-5" style="text-align:right">
<h3 style="padding-right:0.5em"> <h3 style="padding-right:0.5em">
<form data-onsubmit="return_false" action="/token_ajax?action=revoke_token&session=<%= token[:session] %>&referer=<%= env.get("current_page") %>" method="post"> <form data-onsubmit="return_false" action="/token_ajax?action=revoke_token&session=<%= token[:session] %>&referer=<%= env.get("current_page") %>" method="post">
<input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= HTML.escape(env.get?("csrf_token").try &.as(String) || "") %>">
<input style="all:unset" type="submit" data-onclick="revoke_token" data-session="<%= token[:session] %>" value="<%= translate(locale, "revoke") %>"> <input style="all:unset" type="submit" data-onclick="revoke_token" data-session="<%= token[:session] %>" value="<%= I18n.translate(locale, "revoke") %>">
</form> </form>
</h3> </h3>
</div> </div>

View File

@ -35,11 +35,11 @@ we're going to need to do it here in order to allow for translations.
--> -->
<style> <style>
#descexpansionbutton ~ label > a::after { #descexpansionbutton ~ label > a::after {
content: "<%= translate(locale, "Show more") %>" content: "<%= I18n.translate(locale, "Show more") %>"
} }
#descexpansionbutton:checked ~ label > a::after { #descexpansionbutton:checked ~ label > a::after {
content: "<%= translate(locale, "Show less") %>" content: "<%= I18n.translate(locale, "Show less") %>"
} }
</style> </style>
<% end %> <% end %>
@ -53,12 +53,12 @@ we're going to need to do it here in order to allow for translations.
"length_seconds" => video.length_seconds.to_f, "length_seconds" => video.length_seconds.to_f,
"play_next" => !video.related_videos.empty? && !plid && params.continue, "play_next" => !video.related_videos.empty? && !plid && params.continue,
"next_video" => video.related_videos.select { |rv| rv["id"]? }[0]?.try &.["id"], "next_video" => video.related_videos.select { |rv| rv["id"]? }[0]?.try &.["id"],
"youtube_comments_text" => HTML.escape(translate(locale, "View YouTube comments")), "youtube_comments_text" => HTML.escape(I18n.translate(locale, "View YouTube comments")),
"reddit_comments_text" => HTML.escape(translate(locale, "View Reddit comments")), "reddit_comments_text" => HTML.escape(I18n.translate(locale, "View Reddit comments")),
"reddit_permalink_text" => HTML.escape(translate(locale, "View more comments on Reddit")), "reddit_permalink_text" => HTML.escape(I18n.translate(locale, "View more comments on Reddit")),
"comments_text" => HTML.escape(translate(locale, "View `x` comments", "{commentCount}")), "comments_text" => HTML.escape(I18n.translate(locale, "View `x` comments", "{commentCount}")),
"hide_replies_text" => HTML.escape(translate(locale, "Hide replies")), "hide_replies_text" => HTML.escape(I18n.translate(locale, "Hide replies")),
"show_replies_text" => HTML.escape(translate(locale, "Show replies")), "show_replies_text" => HTML.escape(I18n.translate(locale, "Show replies")),
"params" => params, "params" => params,
"preferences" => preferences, "preferences" => preferences,
"premiere_timestamp" => video.premiere_timestamp.try &.to_unix, "premiere_timestamp" => video.premiere_timestamp.try &.to_unix,
@ -79,11 +79,11 @@ we're going to need to do it here in order to allow for translations.
<h1> <h1>
<%= title %> <%= title %>
<% if params.listen %> <% if params.listen %>
<a title="<%=translate(locale, "Video mode")%>" id="link-iv-listen" data-base-url="/watch?<%= env.params.query %>&listen=0" href="/watch?<%= env.params.query %>&listen=0"> <a title="<%=I18n.translate(locale, "Video mode")%>" id="link-iv-listen" data-base-url="/watch?<%= env.params.query %>&listen=0" href="/watch?<%= env.params.query %>&listen=0">
<i class="icon ion-ios-videocam"></i> <i class="icon ion-ios-videocam"></i>
</a> </a>
<% else %> <% else %>
<a title="<%=translate(locale, "Audio mode")%>" id="link-iv-listen" data-base-url="/watch?<%= env.params.query %>&listen=1" href="/watch?<%= env.params.query %>&listen=1"> <a title="<%=I18n.translate(locale, "Audio mode")%>" id="link-iv-listen" data-base-url="/watch?<%= env.params.query %>&listen=1" href="/watch?<%= env.params.query %>&listen=1">
<i class="icon ion-md-headset"></i> <i class="icon ion-md-headset"></i>
</a> </a>
<% end %> <% end %>
@ -91,7 +91,7 @@ we're going to need to do it here in order to allow for translations.
<% if !video.is_listed %> <% if !video.is_listed %>
<h3> <h3>
<i class="icon ion-ios-unlock"></i> <%= translate(locale, "Unlisted") %> <i class="icon ion-ios-unlock"></i> <%= I18n.translate(locale, "Unlisted") %>
</h3> </h3>
<% end %> <% end %>
@ -101,11 +101,11 @@ we're going to need to do it here in order to allow for translations.
</h3> </h3>
<% elsif video.premiere_timestamp.try &.> Time.utc %> <% elsif video.premiere_timestamp.try &.> Time.utc %>
<h3> <h3>
<%= video.premiere_timestamp.try { |t| translate(locale, "Premieres in `x`", recode_date((t - Time.utc).ago, locale)) } %> <%= video.premiere_timestamp.try { |t| I18n.translate(locale, "Premieres in `x`", recode_date((t - Time.utc).ago, locale)) } %>
</h3> </h3>
<% elsif video.live_now %> <% elsif video.live_now %>
<h3> <h3>
<%= video.premiere_timestamp.try { |t| translate(locale, "videoinfo_started_streaming_x_ago", recode_date((Time.utc - t).ago, locale)) } %> <%= video.premiere_timestamp.try { |t| I18n.translate(locale, "videoinfo_started_streaming_x_ago", recode_date((Time.utc - t).ago, locale)) } %>
</h3> </h3>
<% end %> <% end %>
</div> </div>
@ -124,13 +124,13 @@ we're going to need to do it here in order to allow for translations.
link_yt_embed = IV::HttpServer::Utils.add_params_to_url(link_yt_embed, link_yt_param) link_yt_embed = IV::HttpServer::Utils.add_params_to_url(link_yt_embed, link_yt_param)
end end
-%> -%>
<a id="link-yt-watch" rel="noreferrer noopener" data-base-url="<%= link_yt_watch %>" href="<%= link_yt_watch %>"><%= translate(locale, "videoinfo_watch_on_youTube") %></a> <a id="link-yt-watch" rel="noreferrer noopener" data-base-url="<%= link_yt_watch %>" href="<%= link_yt_watch %>"><%= I18n.translate(locale, "videoinfo_watch_on_youTube") %></a>
(<a id="link-yt-embed" rel="noopener" referrerpolicy="origin-when-cross-origin" data-base-url="<%= link_yt_embed %>" href="<%= link_yt_embed %>"><%= translate(locale, "videoinfo_youTube_embed_link") %></a>) (<a id="link-yt-embed" rel="noopener" data-base-url="<%= link_yt_embed %>" href="<%= link_yt_embed %>"><%= I18n.translate(locale, "videoinfo_youTube_embed_link") %></a>)
</span> </span>
<p id="watch-on-another-invidious-instance"> <p id="watch-on-another-invidious-instance">
<%- link_iv_other = IV::Frontend::Misc.redirect_url(env) -%> <%- link_iv_other = IV::Frontend::Misc.redirect_url(env) -%>
<a id="link-iv-other" data-base-url="<%= link_iv_other %>" href="<%= link_iv_other %>"><%= translate(locale, "Switch Invidious Instance") %></a> <a id="link-iv-other" data-base-url="<%= link_iv_other %>" href="<%= link_iv_other %>"><%= I18n.translate(locale, "Switch Invidious Instance") %></a>
</p> </p>
<p id="embed-link"> <p id="embed-link">
@ -141,17 +141,17 @@ we're going to need to do it here in order to allow for translations.
link_iv_embed = URI.new(path: "/embed/#{id}") link_iv_embed = URI.new(path: "/embed/#{id}")
link_iv_embed = IV::HttpServer::Utils.add_params_to_url(link_iv_embed, params_iv_embed) link_iv_embed = IV::HttpServer::Utils.add_params_to_url(link_iv_embed, params_iv_embed)
-%> -%>
<a id="link-iv-embed" data-base-url="<%= link_iv_embed %>" href="<%= link_iv_embed %>"><%= translate(locale, "videoinfo_invidious_embed_link") %></a> <a id="link-iv-embed" data-base-url="<%= link_iv_embed %>" href="<%= link_iv_embed %>"><%= I18n.translate(locale, "videoinfo_invidious_embed_link") %></a>
</p> </p>
<p id="annotations"> <p id="annotations">
<% if params.annotations %> <% if params.annotations %>
<a href="/watch?<%= env.params.query %>&iv_load_policy=3"> <a href="/watch?<%= env.params.query %>&iv_load_policy=3">
<%= translate(locale, "Hide annotations") %> <%= I18n.translate(locale, "Hide annotations") %>
</a> </a>
<% else %> <% else %>
<a href="/watch?<%= env.params.query %>&iv_load_policy=1"> <a href="/watch?<%= env.params.query %>&iv_load_policy=1">
<%=translate(locale, "Show annotations")%> <%=I18n.translate(locale, "Show annotations")%>
</a> </a>
<% end %> <% end %>
</p> </p>
@ -161,7 +161,7 @@ we're going to need to do it here in order to allow for translations.
<% if !playlists.empty? %> <% if !playlists.empty? %>
<form data-onsubmit="return_false" class="pure-form pure-form-stacked" action="/playlist_ajax?action=add_video" method="post" target="_blank"> <form data-onsubmit="return_false" class="pure-form pure-form-stacked" action="/playlist_ajax?action=add_video" method="post" target="_blank">
<div class="pure-control-group"> <div class="pure-control-group">
<label for="playlist_id"><%= translate(locale, "Add to playlist: ") %></label> <label for="playlist_id"><%= I18n.translate(locale, "Add to playlist: ") %></label>
<select style="width:100%" name="playlist_id" id="playlist_id"> <select style="width:100%" name="playlist_id" id="playlist_id">
<% playlists.each do |plid, playlist_title| %> <% playlists.each do |plid, playlist_title| %>
<option data-plid="<%= plid %>" value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option> <option data-plid="<%= plid %>" value="<%= plid %>" <%= "selected" if user.preferences.default_playlist == plid %>><%= HTML.escape(playlist_title) %></option>
@ -172,7 +172,7 @@ we're going to need to do it here in order to allow for translations.
<input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(env.get?("csrf_token").try &.as(String) || "") %>"> <input type="hidden" name="csrf_token" value="<%= URI.encode_www_form(env.get?("csrf_token").try &.as(String) || "") %>">
<input type="hidden" name="video_id" value="<%= video.id %>"> <input type="hidden" name="video_id" value="<%= video.id %>">
<button data-onclick="add_playlist_video" data-id="<%= video.id %>" type="submit" class="pure-button pure-button-primary"> <button data-onclick="add_playlist_video" data-id="<%= video.id %>" type="submit" class="pure-button pure-button-primary">
<b><%= translate(locale, "Add to playlist") %></b> <b><%= I18n.translate(locale, "Add to playlist") %></b>
</button> </button>
</form> </form>
<script id="playlist_data" type="application/json"> <script id="playlist_data" type="application/json">
@ -191,7 +191,7 @@ we're going to need to do it here in order to allow for translations.
<p id="views"><i class="icon ion-ios-eye"></i> <%= number_with_separator(video.views) %></p> <p id="views"><i class="icon ion-ios-eye"></i> <%= number_with_separator(video.views) %></p>
<p id="likes"><i class="icon ion-ios-thumbs-up"></i> <%= number_with_separator(video.likes) %></p> <p id="likes"><i class="icon ion-ios-thumbs-up"></i> <%= number_with_separator(video.likes) %></p>
<p id="dislikes" style="display: none; visibility: hidden;"></p> <p id="dislikes" style="display: none; visibility: hidden;"></p>
<p id="genre"><%= translate(locale, "Genre: ") %> <p id="genre"><%= I18n.translate(locale, "Genre: ") %>
<% if !video.genre_url %> <% if !video.genre_url %>
<%= video.genre %> <%= video.genre %>
<% else %> <% else %>
@ -200,21 +200,21 @@ we're going to need to do it here in order to allow for translations.
</p> </p>
<% if video.license %> <% if video.license %>
<% if video.license.empty? %> <% if video.license.empty? %>
<p id="license"><%= translate(locale, "License: ") %><%= translate(locale, "Standard YouTube license") %></p> <p id="license"><%= I18n.translate(locale, "License: ") %><%= I18n.translate(locale, "Standard YouTube license") %></p>
<% else %> <% else %>
<p id="license"><%= translate(locale, "License: ") %><%= video.license %></p> <p id="license"><%= I18n.translate(locale, "License: ") %><%= video.license %></p>
<% end %> <% end %>
<% end %> <% end %>
<p id="family_friendly"><%= translate(locale, "Family friendly? ") %><%= translate_bool(locale, video.is_family_friendly) %></p> <p id="family_friendly"><%= I18n.translate(locale, "Family friendly? ") %><%= I18n.translate_bool(locale, video.is_family_friendly) %></p>
<p id="wilson" style="display: none; visibility: hidden;"></p> <p id="wilson" style="display: none; visibility: hidden;"></p>
<p id="rating" style="display: none; visibility: hidden;"></p> <p id="rating" style="display: none; visibility: hidden;"></p>
<p id="engagement" style="display: none; visibility: hidden;"></p> <p id="engagement" style="display: none; visibility: hidden;"></p>
<% if video.allowed_regions.size != REGIONS.size %> <% if video.allowed_regions.size != REGIONS.size %>
<p id="allowed_regions"> <p id="allowed_regions">
<% if video.allowed_regions.size < REGIONS.size // 2 %> <% if video.allowed_regions.size < REGIONS.size // 2 %>
<%= translate(locale, "Whitelisted regions: ") %><%= video.allowed_regions.join(", ") %> <%= I18n.translate(locale, "Whitelisted regions: ") %><%= video.allowed_regions.join(", ") %>
<% else %> <% else %>
<%= translate(locale, "Blacklisted regions: ") %><%= (REGIONS.to_a - video.allowed_regions).join(", ") %> <%= I18n.translate(locale, "Blacklisted regions: ") %><%= (REGIONS.to_a - video.allowed_regions).join(", ") %>
<% end %> <% end %>
</p> </p>
<% end %> <% end %>
@ -246,9 +246,9 @@ we're going to need to do it here in order to allow for translations.
<div class="h-box"> <div class="h-box">
<p id="published-date"> <p id="published-date">
<% if video.premiere_timestamp.try &.> Time.utc %> <% if video.premiere_timestamp.try &.> Time.utc %>
<b><%= video.premiere_timestamp.try { |t| translate(locale, "Premieres `x`", t.to_s("%B %-d, %R UTC")) } %></b> <b><%= video.premiere_timestamp.try { |t| I18n.translate(locale, "Premieres `x`", t.to_s("%B %-d, %R UTC")) } %></b>
<% else %> <% else %>
<b><%= translate(locale, "Shared `x`", video.published.to_s("%B %-d, %Y")) %></b> <b><%= I18n.translate(locale, "Shared `x`", video.published.to_s("%B %-d, %Y")) %></b>
<% end %> <% end %>
</p> </p>
@ -270,7 +270,7 @@ we're going to need to do it here in order to allow for translations.
<input id="music-desc-expansion" type="checkbox"/> <input id="music-desc-expansion" type="checkbox"/>
<label for="music-desc-expansion"> <label for="music-desc-expansion">
<h3 id="music-description-title"> <h3 id="music-description-title">
<%= translate(locale, "Music in this video") %> <%= I18n.translate(locale, "Music in this video") %>
<span class="icon ion-ios-arrow-up"></span> <span class="icon ion-ios-arrow-up"></span>
<span class="icon ion-ios-arrow-down"></span> <span class="icon ion-ios-arrow-down"></span>
</h3> </h3>
@ -279,9 +279,9 @@ we're going to need to do it here in order to allow for translations.
<div id="music-description-box"> <div id="music-description-box">
<% video.music.each do |music| %> <% video.music.each do |music| %>
<div class="music-item"> <div class="music-item">
<p class="music-song"><%= translate(locale, "Song: ") %><%= music.song %></p> <p class="music-song"><%= I18n.translate(locale, "Song: ") %><%= music.song %></p>
<p class="music-artist"><%= translate(locale, "Artist: ") %><%= music.artist %></p> <p class="music-artist"><%= I18n.translate(locale, "Artist: ") %><%= music.artist %></p>
<p class="music-album"><%= translate(locale, "Album: ") %><%= music.album %></p> <p class="music-album"><%= I18n.translate(locale, "Album: ") %><%= music.album %></p>
</div> </div>
<% end %> <% end %>
</div> </div>
@ -294,7 +294,7 @@ we're going to need to do it here in order to allow for translations.
<% else %> <% else %>
<noscript> <noscript>
<a href="/watch?<%= env.params.query %>&nojs=1"> <a href="/watch?<%= env.params.query %>&nojs=1">
<%= translate(locale, "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.") %> <%= I18n.translate(locale, "Hi! Looks like you have JavaScript turned off. Click here to view comments, keep in mind they may take a bit longer to load.") %>
</a> </a>
</noscript> </noscript>
<% end %> <% end %>
@ -313,7 +313,7 @@ we're going to need to do it here in order to allow for translations.
<% if !video.related_videos.empty? %> <% if !video.related_videos.empty? %>
<div <% if plid %>style="display:none"<% end %>> <div <% if plid %>style="display:none"<% end %>>
<div class="pure-control-group"> <div class="pure-control-group">
<label for="continue"><%= translate(locale, "preferences_continue_label") %></label> <label for="continue"><%= I18n.translate(locale, "preferences_continue_label") %></label>
<input name="continue" id="continue" type="checkbox" <% if params.continue %>checked<% end %>> <input name="continue" id="continue" type="checkbox" <% if params.continue %>checked<% end %>>
</div> </div>
<hr> <hr>
@ -356,7 +356,7 @@ we're going to need to do it here in order to allow for translations.
<div class="pure-u-10-24" style="text-align:right"> <div class="pure-u-10-24" style="text-align:right">
<b class="width:100%"><%= <b class="width:100%"><%=
views = short_text_to_number(rv["short_view_count"]? || "0") views = short_text_to_number(rv["short_view_count"]? || "0")
translate_count(locale, "generic_views_count", views, NumberFormatting::Short) I18n.translate_count(locale, "generic_views_count", views, I18n::NumberFormatting::Short)
%></b> %></b>
</div> </div>
</h5> </h5>