Compare commits
21 Commits
dependabot
...
main
Author | SHA1 | Date | |
---|---|---|---|
fe5c0d5113 | |||
3ae870047a | |||
2a360a6875 | |||
bd04bb63a1 | |||
5f98d9ebfd | |||
9ef2a92d60 | |||
03c957e654 | |||
b2cc7e7016 | |||
da2f4f6c86 | |||
3661d2b008 | |||
0e476b546d | |||
d331a73a85 | |||
5a82fc9a10 | |||
926ba18e85 | |||
09fa1ceea9 | |||
5b996bb64a | |||
80ceac5d94 | |||
bd42833953 | |||
f6b9dcf187 | |||
517e3038cc | |||
9fe92b1fc4 |
4
.github/workflows/docker-dev.yml
vendored
4
.github/workflows/docker-dev.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Docker
|
||||
name: Docker Dev
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -45,4 +45,4 @@ jobs:
|
||||
context: .
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: |
|
||||
${{ env.REGISTRY }}/${{github.actor}}/${{ github.event.repository.name }}:dev
|
||||
${{ env.REGISTRY }}/${{github.actor}}/${{ github.event.repository.name }}_dev:dev
|
2
.github/workflows/docker-main.yml
vendored
2
.github/workflows/docker-main.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: Docker
|
||||
name: Docker Main
|
||||
|
||||
on:
|
||||
push:
|
||||
|
@ -1 +1 @@
|
||||
ruby-3.3.5
|
||||
3.3.5
|
||||
|
2
Gemfile
2
Gemfile
@ -67,6 +67,8 @@ gem "mini_magick", "~> 4.13.2"
|
||||
|
||||
gem "redis", "~> 5.3"
|
||||
|
||||
gem "builder", "~> 3.3"
|
||||
|
||||
group :development, :test do
|
||||
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
|
||||
gem "debug", platforms: %i[ mri windows ], require: "debug/prelude"
|
||||
|
@ -523,6 +523,7 @@ DEPENDENCIES
|
||||
aws-sdk-s3 (~> 1.170)
|
||||
bootsnap
|
||||
brakeman
|
||||
builder (~> 3.3)
|
||||
bullet (~> 8.0)
|
||||
capybara
|
||||
cssbundling-rails
|
||||
|
@ -2,6 +2,7 @@ class ApplicationController < ActionController::Base
|
||||
include SeoConcern
|
||||
# Only allow modern browsers supporting webp images, web push, badges, import maps, CSS nesting, and CSS :has.
|
||||
before_action :log_browser_info
|
||||
before_action :set_content_type_for_rss, if: -> { request.format.rss? }
|
||||
# allow_browser versions: :modern
|
||||
# allow_browser versions: :modern,
|
||||
# patterns: [
|
||||
@ -47,7 +48,7 @@ class ApplicationController < ActionController::Base
|
||||
# Bot: #{browser.bot?}
|
||||
# BROWSER_INFO
|
||||
# }
|
||||
before_action :set_locale
|
||||
around_action :set_locale
|
||||
after_action :track_action
|
||||
|
||||
def log_browser_info
|
||||
@ -75,7 +76,55 @@ class ApplicationController < ActionController::Base
|
||||
|
||||
private
|
||||
|
||||
def set_locale
|
||||
I18n.locale = params[:locale] || I18n.default_locale
|
||||
def set_locale(&action)
|
||||
I18n.locale = extract_locale || I18n.default_locale
|
||||
I18n.fallbacks[I18n.locale] = [ I18n.locale, I18n.default_locale ].uniq
|
||||
locale = params[:locale] || extract_locale_from_accept_language_header || I18n.default_locale
|
||||
I18n.with_locale(locale, &action)
|
||||
# 重定向到带有语言前缀的相同路径
|
||||
# redirect_to "/#{locale}#{request.fullpath}"
|
||||
end
|
||||
|
||||
def extract_locale_from_accept_language_header
|
||||
return I18n.default_locale.to_s unless request.env["HTTP_ACCEPT_LANGUAGE"]
|
||||
|
||||
available_locales = I18n.available_locales.map(&:to_s)
|
||||
|
||||
accept_language = request.env["HTTP_ACCEPT_LANGUAGE"].to_s
|
||||
# 修改正则表达式以匹配 'zh-CN' 这样的格式
|
||||
if (full_locale = accept_language.scan(/^[a-z]{2}-[A-Z]{2}/).first)
|
||||
locale = full_locale
|
||||
else
|
||||
# 否则只匹配语言代码 (例如 'en')
|
||||
locale = accept_language.scan(/^[a-z]{2}/).first || I18n.default_locale.to_s
|
||||
end
|
||||
|
||||
return locale if available_locales.include?(locale)
|
||||
|
||||
# 尝试基础语言匹配(例如:当请求 'zh' 时匹配 'zh-CN')
|
||||
base_language = locale.split("-").first
|
||||
matching_locale = available_locales.find do |available_locale|
|
||||
available_locale.start_with?(base_language)
|
||||
end
|
||||
matching_locale ? matching_locale : I18n.default_locale.to_s
|
||||
end
|
||||
|
||||
def sanitize_locale(locale)
|
||||
# 直接使用 I18n.available_locales
|
||||
locale = locale.to_sym
|
||||
I18n.available_locales.include?(locale) ? locale : I18n.default_locale
|
||||
end
|
||||
|
||||
def extract_locale
|
||||
parsed_locale = params[:locale]
|
||||
I18n.available_locales.map(&:to_s).include?(parsed_locale) ? parsed_locale : nil
|
||||
end
|
||||
|
||||
def default_url_options
|
||||
{ locale: I18n.locale }
|
||||
end
|
||||
|
||||
def set_content_type_for_rss
|
||||
response.headers["Content-Type"] = "application/rss+xml; charset=utf-8"
|
||||
end
|
||||
end
|
||||
|
@ -46,7 +46,7 @@ class CitiesController < ApplicationController
|
||||
set_meta_tags(
|
||||
title: @city.name,
|
||||
description: "Experience #{@city.name}'s weather through AI-generated art. Daily updates of weather conditions visualized through artificial intelligence.",
|
||||
keywords: "#{@city.name}, #{@city.country.name}, weather art, AI visualization",
|
||||
keywords: "#{@city.name}, #{@city.country.name}, ai, ai web, ai art, ai weather, weather art, AI visualization",
|
||||
og: {
|
||||
image: @city.latest_weather_art&.image&.attached? ? url_for(@city.latest_weather_art.image) : nil
|
||||
}
|
||||
|
9
app/controllers/rss_controller.rb
Normal file
9
app/controllers/rss_controller.rb
Normal file
@ -0,0 +1,9 @@
|
||||
class RssController < ApplicationController
|
||||
def feed
|
||||
@weather_arts = WeatherArt.order(created_at: :desc).limit(20)
|
||||
|
||||
respond_to do |format|
|
||||
format.rss { render layout: false }
|
||||
end
|
||||
end
|
||||
end
|
@ -1,33 +1,126 @@
|
||||
class SitemapsController < ApplicationController
|
||||
include SitemapsHelper
|
||||
before_action :set_bucket_name
|
||||
|
||||
def index
|
||||
@sitemaps = list_sitemaps
|
||||
respond_to do |format|
|
||||
format.html
|
||||
format.xml { render_sitemap_index }
|
||||
end
|
||||
rescue Aws::S3::Errors::ServiceError => e
|
||||
Rails.logger.error "S3 Error: #{e.message}"
|
||||
render status: :internal_server_error
|
||||
end
|
||||
|
||||
def show
|
||||
path = params[:path]
|
||||
bucket_name =
|
||||
Rails.env.production? ?
|
||||
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)) :
|
||||
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:minio_dev, :bucket))
|
||||
Rails.logger.info "Sitemap: #{path}"
|
||||
key = "sitemaps/#{path}"
|
||||
|
||||
Rails.logger.info "Requesting sitemap: #{path}"
|
||||
|
||||
begin
|
||||
s3_client = Aws::S3::Client.new
|
||||
response = s3_client.get_object(
|
||||
bucket: bucket_name,
|
||||
key: "sitemaps/#{path}"
|
||||
# 检查文件是否存在
|
||||
s3_client.head_object(
|
||||
bucket: @bucket_name,
|
||||
key: key
|
||||
)
|
||||
|
||||
expires_in 12.hours, public: true
|
||||
content_type = response.content_type || "application/xml"
|
||||
|
||||
send_data(
|
||||
response.body.read,
|
||||
filename: path,
|
||||
type: content_type,
|
||||
disposition: "inline"
|
||||
# 生成预签名URL,设置15分钟有效期
|
||||
signer = Aws::S3::Presigner.new(client: s3_client)
|
||||
url = signer.presigned_url(
|
||||
:get_object,
|
||||
bucket: @bucket_name,
|
||||
key: key,
|
||||
expires_in: 15 * 60, # 15 minutes
|
||||
# response_content_type: 'application/xml', # 确保正确的内容类型
|
||||
response_content_disposition: "inline" # 在浏览器中直接显示
|
||||
)
|
||||
rescue Aws::S3::Errors::NoSuchKey
|
||||
|
||||
# 设置缓存头
|
||||
response.headers["Cache-Control"] = "public, max-age=3600" # 1小时缓存
|
||||
|
||||
# 重定向到预签名URL
|
||||
redirect_to url, allow_other_host: true, status: :found
|
||||
|
||||
rescue Aws::S3::Errors::NotFound
|
||||
Rails.logger.error "Sitemap not found: #{path}"
|
||||
render status: :not_found
|
||||
rescue Aws::S3::Errors::ServiceError => e
|
||||
Rails.logger.error "S3 Error: #{e.message}"
|
||||
render status: :internal_server_error
|
||||
end
|
||||
end
|
||||
|
||||
# def show
|
||||
# path = params[:path]
|
||||
# Rails.logger.info "Sitemap: #{path}"
|
||||
|
||||
# begin
|
||||
# response = s3_client.get_object(
|
||||
# bucket: @bucket_name,
|
||||
# key: "sitemaps/#{path}"
|
||||
# )
|
||||
|
||||
# expires_in 12.hours, public: true
|
||||
# content_type = response.content_type || "application/xml"
|
||||
|
||||
# send_data(
|
||||
# response.body.read,
|
||||
# filename: path,
|
||||
# type: content_type,
|
||||
# disposition: "inline"
|
||||
# )
|
||||
# rescue Aws::S3::Errors::NoSuchKey
|
||||
# render status: :not_found
|
||||
# rescue Aws::S3::Errors::ServiceError => e
|
||||
# Rails.logger.error "S3 Error: #{e.message}"
|
||||
# render status: :internal_server_error
|
||||
# end
|
||||
# end
|
||||
|
||||
private
|
||||
|
||||
def set_bucket_name
|
||||
@bucket_name = Rails.env.production? ?
|
||||
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)) :
|
||||
ENV.fetch("AWS_DEV_BUCKET", Rails.application.credentials.dig(:minio_dev, :bucket))
|
||||
end
|
||||
|
||||
def s3_client
|
||||
@s3_client ||= Aws::S3::Client.new
|
||||
end
|
||||
|
||||
def list_sitemaps
|
||||
response = s3_client.list_objects_v2(
|
||||
bucket: @bucket_name,
|
||||
prefix: "sitemaps/"
|
||||
)
|
||||
|
||||
response.contents.map do |object|
|
||||
{
|
||||
key: object.key.sub("sitemaps/", ""),
|
||||
last_modified: object.last_modified,
|
||||
size: object.size,
|
||||
url: sitemap_url(object.key.sub("sitemaps/", ""))
|
||||
}
|
||||
end.reject { |obj| obj[:key].empty? }
|
||||
end
|
||||
|
||||
def render_sitemap_index
|
||||
base_url = "#{request.protocol}#{request.host_with_port}"
|
||||
|
||||
builder = Nokogiri::XML::Builder.new(encoding: "UTF-8") do |xml|
|
||||
xml.sitemapindex(xmlns: "http://www.sitemaps.org/schemas/sitemap/0.9") do
|
||||
@sitemaps.each do |sitemap|
|
||||
xml.sitemap do
|
||||
xml.loc "#{base_url}/sitemaps/#{sitemap[:key]}"
|
||||
xml.lastmod sitemap[:last_modified].iso8601
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
render xml: builder.to_xml
|
||||
end
|
||||
end
|
||||
|
@ -17,7 +17,7 @@ class WeatherArtsController < ApplicationController
|
||||
set_meta_tags(
|
||||
title: "#{@city.name} Weather Art - #{@weather_art.weather_date.strftime('%B %d, %Y')}",
|
||||
description: "#{@city.name}'s weather visualized through AI art. #{@weather_art.description} at #{@weather_art.temperature}°C.",
|
||||
keywords: "#{@city.name}, weather art, #{@weather_art.description}, AI visualization",
|
||||
keywords: "#{@city.name}, #{@city.country.name}, ai, ai web, ai art, ai weather, weather art, AI visualization, #{@weather_art.description}",
|
||||
og: {
|
||||
image: @weather_art.image.attached? ? url_for(@weather_art.image) : nil
|
||||
}
|
||||
|
2
app/helpers/rss_helper.rb
Normal file
2
app/helpers/rss_helper.rb
Normal file
@ -0,0 +1,2 @@
|
||||
module RssHelper
|
||||
end
|
@ -1,2 +1,5 @@
|
||||
module SitemapsHelper
|
||||
def sitemap_url(filename)
|
||||
"/sitemaps/#{filename}"
|
||||
end
|
||||
end
|
||||
|
22
app/models/concerns/translatable_name.rb
Normal file
22
app/models/concerns/translatable_name.rb
Normal file
@ -0,0 +1,22 @@
|
||||
# app/models/concerns/translatable_name.rb
|
||||
module TranslatableName
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def localized_name(default_locale = "en")
|
||||
return name unless translations.present?
|
||||
|
||||
translations_hash = translations.is_a?(String) ? JSON.parse(translations) : translations
|
||||
|
||||
# 尝试完全匹配当前语言设置
|
||||
current_locale = I18n.locale.to_s
|
||||
return translations_hash[current_locale] if translations_hash[current_locale].present?
|
||||
|
||||
# 尝试匹配语言的基础部分(例如 'zh-CN' => 'zh')
|
||||
base_locale = current_locale.split("-").first
|
||||
matching_key = translations_hash.keys.find { |k| k.start_with?(base_locale) }
|
||||
return translations_hash[matching_key] if matching_key.present?
|
||||
|
||||
# 如果没有匹配,返回默认语言的翻译或原始名称
|
||||
translations_hash[default_locale] || name
|
||||
end
|
||||
end
|
@ -1,8 +1,9 @@
|
||||
class Country < ApplicationRecord
|
||||
include TranslatableName
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: :slugged
|
||||
|
||||
before_save :format_timezones
|
||||
# before_save :format_json_attributes, :timezones, :translations
|
||||
|
||||
belongs_to :region, optional: true
|
||||
belongs_to :subregion, optional: true
|
||||
@ -13,14 +14,15 @@ class Country < ApplicationRecord
|
||||
validates :code, presence: true, uniqueness: true
|
||||
validates :iso2, uniqueness: true, allow_blank: true
|
||||
|
||||
serialize :translations, coder: JSON
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
|
||||
def localized_name
|
||||
I18n.t("countries.#{code}")
|
||||
end
|
||||
# def localized_name
|
||||
# I18n.t("countries.#{code}")
|
||||
# end
|
||||
|
||||
def self.ransackable_attributes(auth_object = nil)
|
||||
[ "code", "created_at", "id", "id_value", "name", "region_id", "slug", "updated_at" ]
|
||||
@ -32,26 +34,26 @@ class Country < ApplicationRecord
|
||||
|
||||
private
|
||||
|
||||
def format_timezones
|
||||
return unless timezones.is_a?(String)
|
||||
|
||||
# 使用正则替换 => 为 :
|
||||
json_string = timezones.gsub(/=>/, ":")
|
||||
|
||||
# 清理多余的空格
|
||||
json_string = json_string.gsub(/\s+/, " ").strip
|
||||
|
||||
begin
|
||||
# 验证是否为有效的 JSON
|
||||
parsed_json = JSON.parse(json_string)
|
||||
self.timezones = parsed_json.to_json
|
||||
rescue JSON::ParserError
|
||||
# 如果转换失败,可以选择:
|
||||
# 1. 保持原值
|
||||
# 2. 设置为空数组
|
||||
# 3. 记录错误日志
|
||||
Rails.logger.error("Invalid JSON format for country #{id}: #{timezones}")
|
||||
self.timezones = "[]"
|
||||
end
|
||||
end
|
||||
# def format_timezones
|
||||
# return unless timezones.is_a?(String)
|
||||
#
|
||||
# # 使用正则替换 => 为 :
|
||||
# json_string = timezones.gsub(/=>/, ":")
|
||||
#
|
||||
# # 清理多余的空格
|
||||
# json_string = json_string.gsub(/\s+/, " ").strip
|
||||
#
|
||||
# begin
|
||||
# # 验证是否为有效的 JSON
|
||||
# parsed_json = JSON.parse(json_string)
|
||||
# self.timezones = parsed_json.to_json
|
||||
# rescue JSON::ParserError
|
||||
# # 如果转换失败,可以选择:
|
||||
# # 1. 保持原值
|
||||
# # 2. 设置为空数组
|
||||
# # 3. 记录错误日志
|
||||
# Rails.logger.error("Invalid JSON format for country #{id}: #{timezones}")
|
||||
# self.timezones = "[]"
|
||||
# end
|
||||
# end
|
||||
end
|
||||
|
@ -1,4 +1,6 @@
|
||||
class Region < ApplicationRecord
|
||||
include TranslatableName
|
||||
|
||||
extend FriendlyId
|
||||
friendly_id :name, use: :slugged
|
||||
|
||||
@ -9,13 +11,15 @@ class Region < ApplicationRecord
|
||||
validates :name, presence: true, uniqueness: true
|
||||
validates :code, presence: true, uniqueness: true
|
||||
|
||||
serialize :translations, coder: JSON
|
||||
|
||||
def to_s
|
||||
name
|
||||
end
|
||||
|
||||
def localized_name
|
||||
I18n.t("regions.#{code}")
|
||||
end
|
||||
# def localized_name
|
||||
# I18n.t("regions.#{code}")
|
||||
# end
|
||||
|
||||
# 模型中允许被搜索的关联
|
||||
def self.ransackable_associations(auth_object = nil)
|
||||
|
@ -79,11 +79,23 @@ class WeatherArt < ApplicationRecord
|
||||
ActiveSupport::TimeZone["UTC"]
|
||||
time = self.updated_at
|
||||
|
||||
date_string = self.weather_date&.strftime("%B %d, %Y")
|
||||
# 使用 I18n 本地化格式化日期
|
||||
date_string = I18n.l(self.weather_date, format: :long)
|
||||
|
||||
# 格式化时间
|
||||
time_format = use_local_timezone ? time.in_time_zone(time_zone) : time.utc
|
||||
time_string =
|
||||
use_local_timezone ?
|
||||
"#{time.in_time_zone(time_zone).strftime('%H:%M')} #{timezone_info['gmtOffsetName']}" :
|
||||
"#{time.utc.strftime('%H:%M')} UTC"
|
||||
if use_local_timezone
|
||||
I18n.t("time.formats.with_zone",
|
||||
time: I18n.l(time_format, format: :time_only),
|
||||
zone: timezone_info["gmtOffsetName"]
|
||||
)
|
||||
else
|
||||
I18n.t("time.formats.with_zone",
|
||||
time: I18n.l(time_format, format: :time_only),
|
||||
zone: "UTC"
|
||||
)
|
||||
end
|
||||
|
||||
case type
|
||||
when :date
|
||||
@ -91,9 +103,15 @@ class WeatherArt < ApplicationRecord
|
||||
when :time
|
||||
time_string
|
||||
when :all
|
||||
"#{date_string} #{time_string}"
|
||||
I18n.t("time.formats.date_and_time",
|
||||
date: date_string,
|
||||
time: time_string
|
||||
)
|
||||
else
|
||||
"#{date_string} #{time_string}"
|
||||
I18n.t("time.formats.date_and_time",
|
||||
date: date_string,
|
||||
time: time_string
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -17,16 +17,16 @@
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="max-w-3xl mx-auto text-center space-y-6">
|
||||
<h1 class="text-4xl md:text-5xl font-display font-bold">
|
||||
Weather Arts Gallery
|
||||
<%= t("arts.title") %>
|
||||
</h1>
|
||||
<p class="text-xl text-base-content/70">
|
||||
Discover AI-generated weather art from cities around the world
|
||||
<%= t("arts.subtitle") %>
|
||||
</p>
|
||||
|
||||
<!-- 如果有特色图片,显示其信息 -->
|
||||
<% if featured_art %>
|
||||
<div class="text-sm text-base-content/60 pt-4">
|
||||
Latest from <%= featured_art.city.name %>, <%= featured_art.city.country.name %>
|
||||
<%= "#{t("text.latest_from")} #{featured_art.city.full_name}" %>
|
||||
<span class="mx-2">•</span>
|
||||
<%= featured_art.formatted_time(:date) %>
|
||||
</div>
|
||||
@ -47,18 +47,18 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<%= params[:sort] == 'oldest' ? 'Oldest First' : 'Newest First' %>
|
||||
<%= params[:sort] == 'oldest' ? t("text.oldest_first") : t("text.newest_first") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-52">
|
||||
<li>
|
||||
<%= link_to "Newest First", arts_path(sort: 'newest', region: params[:region]),
|
||||
<%= link_to t("text.newest_first"), arts_path(sort: 'newest', region: params[:region]),
|
||||
class: "#{'active' if params[:sort] != 'oldest'}" %>
|
||||
</li>
|
||||
<li>
|
||||
<%= link_to "Oldest First", arts_path(sort: 'oldest', region: params[:region]),
|
||||
<%= link_to t("text.oldest_first"), arts_path(sort: 'oldest', region: params[:region]),
|
||||
class: "#{'active' if params[:sort] == 'oldest'}" %>
|
||||
</li>
|
||||
</ul>
|
||||
@ -70,20 +70,20 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<%= @current_region&.name || 'All Regions' %>
|
||||
<%= @current_region&.localized_name || t("text.all_regions") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-52">
|
||||
<li>
|
||||
<%= link_to "All Regions", arts_path(sort: params[:sort]),
|
||||
<%= link_to t("text.all_regions"), arts_path(sort: params[:sort]),
|
||||
class: "#{'active' unless @current_region}" %>
|
||||
</li>
|
||||
<div class="divider my-1"></div>
|
||||
<% @regions.each do |region| %>
|
||||
<li>
|
||||
<%= link_to region.name, arts_path(region: region.id, sort: params[:sort]),
|
||||
<%= link_to region.localized_name, arts_path(region: region.id, sort: params[:sort]),
|
||||
class: "#{'active' if @current_region == region}" %>
|
||||
</li>
|
||||
<% end %>
|
||||
@ -93,9 +93,9 @@
|
||||
|
||||
<!-- 结果统计 -->
|
||||
<div class="text-center text-sm text-base-content/70 mt-4">
|
||||
Showing <%= @weather_arts.total_count %> weather arts
|
||||
<%= "#{t("text.showing")} #{@weather_arts.total_count} #{t("text.weather_arts")} " %>
|
||||
<% if @current_region %>
|
||||
from <%= @current_region.name %>
|
||||
from <%= @current_region.localized_name %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@ -118,7 +118,7 @@
|
||||
<%= art.city.name %>
|
||||
</h3>
|
||||
<p class="text-sm text-white/80">
|
||||
<%= art.city.country.name %>
|
||||
<%= "#{art.city&.country&.emoji + " " || ""}#{art.city&.country&.localized_name}" %>
|
||||
</p>
|
||||
<div class="flex items-center gap-2 text-white/90">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
@ -154,7 +154,7 @@
|
||||
|
||||
<%= link_to city_weather_art_path(art.city, art),
|
||||
class: "btn btn-primary btn-sm w-full" do %>
|
||||
View Details
|
||||
<%= t("button.view_detail") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
|
@ -75,7 +75,7 @@
|
||||
<div class="card-actions justify-end">
|
||||
<%= link_to city_path(city),
|
||||
class: "btn btn-primary btn-sm gap-2", data: { turbo_frame: "_top" } do %>
|
||||
View Details
|
||||
<%= t("button.view_detail") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
@ -115,7 +115,7 @@
|
||||
<div class="card-actions justify-end">
|
||||
<%= link_to city_path(city),
|
||||
class: "btn btn-primary btn-sm gap-2", data: { turbo_frame: "_top" } do %>
|
||||
View Details
|
||||
<%= t("button.view_detail") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
|
@ -18,7 +18,7 @@
|
||||
<%= f.text_field :query,
|
||||
value: params[:query] ? URI.decode_www_form_component(params[:query]) : nil,
|
||||
class: "w-full pl-12 pr-12 py-3 rounded-full bg-base-200/80 backdrop-blur border border-base-300 focus:outline-none focus:ring-2 focus:ring-primary/50 transition",
|
||||
placeholder: "Search cities...",
|
||||
placeholder: t("text.search_cities"),
|
||||
autocomplete: "off",
|
||||
data: {
|
||||
action: "input->search#submit",
|
||||
|
@ -16,18 +16,18 @@
|
||||
<div class="container mx-auto px-4">
|
||||
<div class="max-w-3xl mx-auto text-center space-y-6">
|
||||
<h1 class="text-5xl md:text-6xl font-display font-bold leading-tight">
|
||||
Explore Cities
|
||||
<%= t("cities.title") %>
|
||||
</h1>
|
||||
<p class="text-xl md:text-2xl text-base-content/70 font-light max-w-2xl mx-auto">
|
||||
Discover AI-generated weather art from cities around the world
|
||||
<%= t("arts.subtitle") %>
|
||||
</p>
|
||||
|
||||
<!-- 特色图片信息 -->
|
||||
<% if featured_art %>
|
||||
<div class="inline-block mt-6 px-4 py-2 bg-base-100/80 backdrop-blur-sm rounded-full text-sm">
|
||||
Latest from
|
||||
<%= t("text.latest_from") %>
|
||||
<span class="font-semibold"><%= featured_art.city.name %></span>,
|
||||
<%= featured_art.city.country.name %>
|
||||
<%= featured_art.city.country.localized_name %>
|
||||
<span class="mx-2">•</span>
|
||||
<%= featured_art.formatted_time(:date) %>
|
||||
</div>
|
||||
@ -50,7 +50,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" />
|
||||
</svg>
|
||||
<%= @current_region&.name || 'All Regions' %>
|
||||
<%= @current_region&.localized_name || t("text.all_regions") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
@ -59,13 +59,13 @@
|
||||
<li>
|
||||
<%= link_to cities_path,
|
||||
class: "#{@current_region ? '' : 'active'}" do %>
|
||||
All Regions
|
||||
<%= t("text.all_regions") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<div class="divider my-1"></div>
|
||||
<% @regions.each do |region| %>
|
||||
<li>
|
||||
<%= link_to region.name,
|
||||
<%= link_to region.localized_name,
|
||||
cities_path(region: region.slug),
|
||||
class: "#{@current_region == region ? 'active' : ''}" %>
|
||||
</li>
|
||||
@ -79,21 +79,21 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 21v-4m0 0V5a2 2 0 012-2h6.5l1 1H21l-3 6 3 6h-8.5l-1-1H5a2 2 0 00-2 2zm9-13.5V9" />
|
||||
</svg>
|
||||
<%= @current_country&.name || "All Countries" %>
|
||||
<%= @current_country&.localized_name || t("text.all_countries") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
|
||||
</svg>
|
||||
</button>
|
||||
<ul class="dropdown-content z-[1] menu p-2 shadow-lg bg-base-100 rounded-box w-52 max-h-80 overflow-y-auto flex-nowrap">
|
||||
<li>
|
||||
<%= link_to "All in #{@current_region.name}",
|
||||
<%= link_to "#{t("text.all_in")} #{@current_region.localized_name}",
|
||||
cities_path(region: @current_region.slug),
|
||||
class: "#{@current_country ? '' : 'active'}" %>
|
||||
</li>
|
||||
<div class="divider my-1"></div>
|
||||
<% @current_region.countries.order(:name).each do |country| %>
|
||||
<li>
|
||||
<%= link_to "#{country&.emoji + " " || ""}#{country.name}",
|
||||
<%= link_to "#{country&.emoji + " " || ""}#{country.localized_name}",
|
||||
cities_path(region: @current_region.slug, country: country.slug),
|
||||
class: "#{@current_country == country ? 'active' : ''}" %>
|
||||
</li>
|
||||
@ -106,9 +106,9 @@
|
||||
<div class="text-sm text-base-content/70 hidden">
|
||||
<%= @cities.count %> <%= 'city'.pluralize(@cities.count) %>
|
||||
<% if @current_country %>
|
||||
in <%= @current_country.name %>
|
||||
in <%= @current_country.localized_name %>
|
||||
<% elsif @current_region %>
|
||||
in <%= @current_region.name %>
|
||||
in <%= @current_region.localized_name %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -16,7 +16,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Back to Cities
|
||||
<%= t("button.back_to_cities") %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
|
@ -20,7 +20,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-actions justify-end mt-4">
|
||||
<%= link_to "View Details", city_weather_art_path(art.city, art),
|
||||
<%= link_to t("button.view_detail"), city_weather_art_path(art.city, art),
|
||||
class: "btn btn-primary btn-outline" %>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -11,13 +11,12 @@
|
||||
<div class="container mx-auto px-4 h-full flex items-center relative">
|
||||
<div class="max-w-2xl space-y-6">
|
||||
<h1 class="text-5xl md:text-6xl font-display font-bold leading-tight">
|
||||
Where Weather Meets<br>Artificial Intelligence
|
||||
<%= t("home.headline_html") %>
|
||||
</h1>
|
||||
<p class="text-xl text-base-content/70 font-sans">
|
||||
Experience weather through the lens of AI-generated art,
|
||||
bringing a new perspective to daily meteorological phenomena.
|
||||
<%= t("home.subtitle") %>
|
||||
</p>
|
||||
<%= link_to "Explore Cities", cities_path,
|
||||
<%= link_to t("button.explore_cities"), cities_path,
|
||||
class: "btn btn-primary btn-lg mt-8 font-sans" %>
|
||||
</div>
|
||||
</div>
|
||||
@ -25,9 +24,9 @@
|
||||
|
||||
<!-- 最新天气艺术 -->
|
||||
<section class="container mx-auto px-4 py-16 space-y-12">
|
||||
<h2 class="text-3xl font-display font-bold text-center">Latest Weather Art</h2>
|
||||
<h2 class="text-3xl font-display font-bold text-center"><%= t("title.latest_weather_art") %></h2>
|
||||
<%= render 'home/arts', arts: @latest_arts %>
|
||||
<h2 class="text-3xl font-display font-bold text-center">Popular Weather Art</h2>
|
||||
<h2 class="text-3xl font-display font-bold text-center"><%= t("title.popular_weather_art") %></h2>
|
||||
<%= render 'home/arts', arts: @popular_arts %>
|
||||
<!-- <h2 class="text-3xl font-display font-bold text-center">Random Weather Art</h2>-->
|
||||
<%#= render 'home/arts', arts: @random_arts %>
|
||||
@ -35,7 +34,7 @@
|
||||
</div>
|
||||
<div class="text-center mt-12 mb-12">
|
||||
<%= link_to arts_path, class: "btn btn-primary btn-lg gap-2" do %>
|
||||
View All Weather Arts
|
||||
<%= t("button.view_all_weather_arts") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7m0 0l-7 7m7-7H3" />
|
||||
</svg>
|
||||
|
@ -1,6 +1,18 @@
|
||||
<!-- 页脚 -->
|
||||
<footer class="footer footer-center p-8 bg-base-200 text-base-content">
|
||||
<div class="container mx-auto flex flex-col gap-2">
|
||||
<div class="container mx-auto flex flex-col gap-4">
|
||||
<!-- 第一行:功能按钮 -->
|
||||
<div class="flex items-center justify-center space-x-4">
|
||||
<%= link_to rss_feed_path(format: :rss), class: "btn btn-ghost btn-sm", title: "RSS Feed" do %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 5c7.18 0 13 5.82 13 13M6 11a7 7 0 017 7m-6 0a1 1 0 11-2 0 1 1 0 012 0z" />
|
||||
</svg>
|
||||
<% end %>
|
||||
|
||||
<%= render 'shared/language_switcher' %>
|
||||
</div>
|
||||
|
||||
<!-- 第二行:统计信息 -->
|
||||
<div id="busuanzi_container" class="text-xs opacity-70">
|
||||
<div class="space-x-2">
|
||||
<span>Page: </span>
|
||||
@ -10,13 +22,14 @@
|
||||
<span>PV <span id="busuanzi_site_pv"></span></span>
|
||||
<span>UV <span id="busuanzi_site_uv"></span></span>
|
||||
<span data-controller="page-load-time">
|
||||
Page Load Time: <span data-page-load-time-target="timer">x</span> ms
|
||||
Load Time: <span data-page-load-time-target="timer">x</span> ms
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="font-display opacity-80">
|
||||
Copyright © 2024 - All rights reserved by AI Weather Art
|
||||
<!-- 第三行:版权信息 -->
|
||||
<p class="font-display opacity-80 text-sm">
|
||||
Copyright © <%= Time.current.year %> - All rights reserved by AI Weather Art
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
</footer>
|
@ -3,14 +3,14 @@
|
||||
<!-- Logo -->
|
||||
<div class="flex-1">
|
||||
<%= link_to root_path, class: "text-xl md:text-2xl font-display font-bold hover:text-primary transition-colors" do %>
|
||||
Today AI Weather
|
||||
<%= t('brand.name') %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
<!-- Desktop Menu -->
|
||||
<div class="hidden md:flex flex-none gap-2 items-center">
|
||||
<%= link_to "Cities", cities_path, class: "btn btn-ghost btn-sm font-sans" %>
|
||||
<%= link_to "Arts", arts_path, class: "btn btn-ghost btn-sm font-sans" %>
|
||||
<%= link_to t("title.cities"), cities_path, class: "btn btn-ghost btn-sm font-sans" %>
|
||||
<%= link_to t("title.arts"), arts_path, class: "btn btn-ghost btn-sm font-sans" %>
|
||||
|
||||
<% if user_signed_in? %>
|
||||
<div class="dropdown dropdown-end">
|
||||
@ -27,12 +27,14 @@
|
||||
</label>
|
||||
<%= render 'layouts/user_menu' %>
|
||||
</div>
|
||||
|
||||
<%= render 'shared/language_switcher' %>
|
||||
<% else %>
|
||||
<%= link_to new_user_session_path, class: "btn btn-primary btn-sm" do %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" />
|
||||
</svg>
|
||||
<span>Sign in</span>
|
||||
<span><%= t("title.sign_in") %></span>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</div>
|
||||
@ -46,8 +48,8 @@
|
||||
</svg>
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content z-[1] menu p-2 shadow bg-base-100 rounded-box w-52">
|
||||
<li><%= link_to "Cities", cities_path %></li>
|
||||
<li><%= link_to "Arts", arts_path %></li>
|
||||
<li><%= link_to t("title.cities"), cities_path %></li>
|
||||
<li><%= link_to t("title.arts"), arts_path %></li>
|
||||
<div class="divider my-1"></div>
|
||||
<% if user_signed_in? %>
|
||||
<li>
|
||||
@ -56,7 +58,7 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
Settings
|
||||
<%= t("title.settings") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<li>
|
||||
@ -67,7 +69,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" />
|
||||
</svg>
|
||||
<span>Sign out</span>
|
||||
<span><% t("title.sign_out") %></span>
|
||||
</div>
|
||||
<% end %>
|
||||
</li>
|
||||
@ -77,7 +79,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15m3 0l3-3m0 0l-3-3m3 3H9" />
|
||||
</svg>
|
||||
Sign in
|
||||
<%= t("title.sign_in") %>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
|
@ -5,7 +5,7 @@
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
||||
</svg>
|
||||
<span>Settings</span>
|
||||
<span><%= t("title.settings") %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M9 12h3.75M9 15h3.75M9 18h3.75m3 .75H18a2.25 2.25 0 002.25-2.25V6.108c0-1.135-.845-2.098-1.976-2.192a48.424 48.424 0 00-1.123-.08m-5.801 0c-.065.21-.1.433-.1.664 0 .414.336.75.75.75h4.5a.75.75 0 00.75-.75 2.25 2.25 0 00-.1-.664m-5.8 0A2.251 2.251 0 0113.5 2.25H15c1.012 0 1.867.668 2.15 1.586m-5.8 0c-.376.023-.75.05-1.124.08C9.095 4.01 8.25 4.973 8.25 6.108V19.5a2.25 2.25 0 002.25 2.25h.75m0-3H21m-3.75 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
|
||||
</svg>
|
||||
<span>Admin Dashboard</span>
|
||||
<span><%= t("title.admin_dashboard") %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
<% end %>
|
||||
@ -29,7 +29,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="w-4 h-4">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 9V5.25A2.25 2.25 0 0013.5 3h-6a2.25 2.25 0 00-2.25 2.25v13.5A2.25 2.25 0 007.5 21h6a2.25 2.25 0 002.25-2.25V15M12 9l-3 3m0 0l3 3m-3-3h12.75" />
|
||||
</svg>
|
||||
<span>Sign out</span>
|
||||
<span><%= t("title.sign_out") %></span>
|
||||
<% end %>
|
||||
</li>
|
||||
</ul>
|
@ -1,5 +1,5 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="<%= I18n.locale %>">
|
||||
<head>
|
||||
<title><%= content_for(:title) || "Today Ai Weather" %></title>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||
@ -11,11 +11,14 @@
|
||||
og: {
|
||||
site_name: 'TodayAIWeather',
|
||||
type: 'website',
|
||||
keywords: "ai, ai web, ai art, ai weather, weather art, AI visualization, today ai weather",
|
||||
url: request.original_url
|
||||
},
|
||||
alternate: {
|
||||
"en" => url_for(locale: 'en'),
|
||||
"zh-CN" => url_for(locale: 'zh-CN'),
|
||||
"en" => url_for(locale: 'en')
|
||||
"ja" => url_for(locale: 'ja'),
|
||||
"ko" => url_for(locale: 'ko')
|
||||
}
|
||||
) %>
|
||||
<%= csrf_meta_tags %>
|
||||
@ -33,6 +36,8 @@
|
||||
<%# Includes all stylesheet files in app/assets/stylesheets %>
|
||||
<%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
|
||||
<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
|
||||
<%= auto_discovery_link_tag :rss, rss_feed_url(format: :rss), title: 'RSS Feed' %>
|
||||
|
||||
<script defer data-domain="todayaiweather.com" src="https://plausible.frytea.com/js/script.js"></script>
|
||||
|
||||
<script defer src="https://busuanzi.frytea.com/js"></script>
|
||||
|
24
app/views/rss/feed.rss.builder
Normal file
24
app/views/rss/feed.rss.builder
Normal file
@ -0,0 +1,24 @@
|
||||
# app/views/rss/feed.rss.builder
|
||||
xml.instruct! :xml, version: "1.0"
|
||||
xml.rss version: "2.0",
|
||||
"xmlns:atom" => "http://www.w3.org/2005/Atom" do
|
||||
xml.channel do
|
||||
xml.title "Today AI Weather Art"
|
||||
xml.description "Daily AI-generated weather art and forecasts"
|
||||
xml.link root_url
|
||||
xml.language "en"
|
||||
xml.atom :link, href: rss_feed_url(format: :rss), rel: "self", type: "application/rss+xml"
|
||||
|
||||
@weather_arts.each do |art|
|
||||
xml.item do
|
||||
xml.title "#{art.city.full_name} Weather Art"
|
||||
xml.description art.description
|
||||
xml.pubDate art.created_at.to_fs(:rfc822)
|
||||
xml.link city_weather_art_url(art.city, art)
|
||||
xml.guid city_weather_art_url(art.city, art)
|
||||
# 如果有图片,添加图片链接
|
||||
xml.enclosure url: rails_blob_url(art.webp_image.processed), type: "image/jpeg" if art.image.attached?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
17
app/views/shared/_language_switcher.html.erb
Normal file
17
app/views/shared/_language_switcher.html.erb
Normal file
@ -0,0 +1,17 @@
|
||||
<%# app/views/shared/_language_switcher.html.erb %>
|
||||
<div class="dropdown dropdown-top">
|
||||
<label tabindex="0" class="btn btn-ghost btn-sm">
|
||||
<%= t("language.#{I18n.locale}") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-1" viewBox="0 0 20 20" fill="currentColor">
|
||||
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
</label>
|
||||
<ul tabindex="0" class="dropdown-content menu p-2 max-h-80 overflow-y-auto flex-nowrap shadow bg-base-100 rounded-box w-32">
|
||||
<% I18n.available_locales.each do |locale| %>
|
||||
<%= link_to url_for(locale: locale),
|
||||
class: "px-4 py-2 hover:bg-base-200 rounded-lg #{I18n.locale == locale ? 'bg-base-200' : ''}" do %>
|
||||
<%= t("language.#{locale}") %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
</ul>
|
||||
</div>
|
@ -78,9 +78,12 @@
|
||||
|
||||
<!-- 结果统计 -->
|
||||
<div class="text-sm text-base-content/60 font-light">
|
||||
Showing <%= collection.offset_value + 1 %> to
|
||||
<%= collection.last_page? ? collection.total_count : collection.offset_value + collection.limit_value %>
|
||||
of <%= collection.total_count %> <%= collection_name || 'items' %>
|
||||
<%= t('pagination.showing_items',
|
||||
from: collection.offset_value + 1,
|
||||
to: collection.last_page? ? collection.total_count : collection.offset_value + collection.limit_value,
|
||||
total: collection.total_count,
|
||||
items: t("pagination.items.#{collection_name}", default: t('pagination.items.default'))
|
||||
) %>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
43
app/views/sitemaps/index.html.erb
Normal file
43
app/views/sitemaps/index.html.erb
Normal file
@ -0,0 +1,43 @@
|
||||
<%# app/views/sitemaps/index.html.erb %>
|
||||
<div class="container mx-auto px-4 py-8">
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<h1 class="text-3xl font-bold mb-6">Sitemaps Index</h1>
|
||||
|
||||
<div class="bg-white rounded-lg shadow overflow-hidden">
|
||||
<div class="overflow-x-auto">
|
||||
<table class="table w-full">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Filename</th>
|
||||
<th>Last Modified</th>
|
||||
<th>Size</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% @sitemaps.each do |sitemap| %>
|
||||
<tr class="hover">
|
||||
<td><%= sitemap[:key] %></td>
|
||||
<td><%= sitemap[:last_modified].strftime("%Y-%m-%d %H:%M:%S") %></td>
|
||||
<td><%= number_to_human_size(sitemap[:size]) %></td>
|
||||
<td>
|
||||
<%= link_to "View", sitemap[:url],
|
||||
class: "btn btn-sm btn-primary",
|
||||
target: "_blank" %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-6 bg-base-200 p-4 rounded-lg">
|
||||
<h2 class="text-xl font-semibold mb-2">For Search Engines</h2>
|
||||
<p class="mb-2">Sitemap Index URL:</p>
|
||||
<code class="block bg-base-300 p-2 rounded">
|
||||
<%= sitemaps_url(format: :xml) %>
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -35,7 +35,7 @@
|
||||
|
||||
<%= link_to city_weather_art_path(weather_art.city, weather_art),
|
||||
class: "btn btn-primary btn-block" do %>
|
||||
View Details
|
||||
<%= t("button.view_detail") %>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-4 w-4 ml-2" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7" />
|
||||
</svg>
|
||||
|
@ -1,37 +1,37 @@
|
||||
<%# Partial _weather_stats.html.erb %>
|
||||
|
||||
<div class="stat bg-gradient-to-br from-primary/10 to-primary/20 hover:from-primary hover:to-primary/30 p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Temperature</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.temperature") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.temperature %>°C</div>
|
||||
<div class="stat-desc">Feels like <%= weather_art.feeling_temp %>°C</div>
|
||||
<div class="stat-desc"><%= t("card.feel_like") %> <%= weather_art.feeling_temp %>°C</div>
|
||||
</div>
|
||||
|
||||
<div class="stat bg-gradient-to-br from-secondary/10 to-secondary/20 hover:from-secondary hover:to-secondary/30 p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Wind</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.wind") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.wind_scale %></div>
|
||||
<div class="stat-desc"><%= weather_art.wind_speed %> km/h</div>
|
||||
</div>
|
||||
|
||||
<div class="stat bg-base-300 hover:bg-base-400 p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Humidity</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.humidity") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.humidity %>%</div>
|
||||
<div class="stat-desc">Relative humidity</div>
|
||||
<div class="stat-desc"><%= t("card.relative_humidity") %></div>
|
||||
</div>
|
||||
|
||||
<div class="stat bg-base-300 hover:bg-base-400 p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Visibility</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.visibility") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.visibility %> km</div>
|
||||
<div class="stat-desc">Clear view distance</div>
|
||||
<div class="stat-desc"><%= t("card.clear_view_distance") %></div>
|
||||
</div>
|
||||
|
||||
<div class="stat bg-accent/10 hover:bg-accent p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Pressure</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.pressure") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.pressure %> hPa</div>
|
||||
<div class="stat-desc">Atmospheric pressure</div>
|
||||
<div class="stat-desc"><%= t("card.atmospheric_pressure") %></div>
|
||||
</div>
|
||||
|
||||
<div class="stat bg-base-200 hover:bg-base-100 p-4 rounded-lg">
|
||||
<div class="stat-title font-medium text-base">Cloud Cover</div>
|
||||
<div class="stat-title font-medium text-base"><%= t("card.cloud_cover") %></div>
|
||||
<div class="stat-value text-3xl"><%= weather_art.cloud %>%</div>
|
||||
<div class="stat-desc">Sky coverage</div>
|
||||
<div class="stat-desc"><%= t("card.sky_coverage") %></div>
|
||||
</div>
|
@ -12,7 +12,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 19l-7-7 7-7" />
|
||||
</svg>
|
||||
Back to <%= @weather_art.city.name %>
|
||||
<%= "#{t("button.back_to")} #{@weather_art.city.name}" %>
|
||||
<% end %>
|
||||
|
||||
<!-- 标题区域 -->
|
||||
@ -23,7 +23,7 @@
|
||||
|
||||
<div class="flex flex-wrap gap-4 mb-6">
|
||||
<div class="badge badge-lg badge-primary">
|
||||
<%= "#{@weather_art&.city&.country&.emoji + " " || ""}#{@city&.country&.name}" %>
|
||||
<%= "#{@weather_art&.city&.country&.emoji + " " || ""}#{@city&.country&.localized_name}" %>
|
||||
</div>
|
||||
<div class="badge badge-lg badge-secondary">
|
||||
<%= @weather_art&.city&.state&.name %>
|
||||
@ -82,7 +82,7 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-6 w-6 text-primary" fill="none" viewBox="0 0 24 24" stroke="currentColor">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 10V3L4 14h7v7l9-11h-7z" />
|
||||
</svg>
|
||||
<h3 class="font-display font-bold text-lg">AI Prompt</h3>
|
||||
<h3 class="font-display font-bold text-lg"><%= t("title.ai_prompt") %></h3>
|
||||
</div>
|
||||
<p class="text-base-content/80 leading-relaxed">
|
||||
<%= @weather_art.prompt %>
|
||||
|
@ -8,6 +8,25 @@ class BatchGenerateWeatherArtsWorker
|
||||
PER_RUN_GENERATION_LIMIT = 2 # 每次运行生成图片上限
|
||||
|
||||
def perform(*args)
|
||||
lock_key = "batch_generate_weather_lock"
|
||||
lock_ttl = 300 # 锁的生存时间,单位为秒
|
||||
|
||||
redis = Redis.new(url: ENV.fetch("REDIS_URL", "redis://localhost:6379/1"))
|
||||
|
||||
if redis.set(lock_key, Time.current.to_s, nx: true, ex: lock_ttl)
|
||||
begin
|
||||
batch_tasks
|
||||
ensure
|
||||
redis.del(lock_key)
|
||||
end
|
||||
else
|
||||
Rails.logger.info "Sitemap refresh is already in progress"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def batch_tasks
|
||||
start_time = Time.current
|
||||
remaining_slots = calculate_remaining_slots
|
||||
return if remaining_slots <= 0
|
||||
@ -38,8 +57,6 @@ class BatchGenerateWeatherArtsWorker
|
||||
print_summary(processed_cities, skipped_cities)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_recent_cities
|
||||
cutoff_time = Time.current - GENERATION_INTERVAL
|
||||
City.joins("LEFT JOIN (
|
||||
|
@ -10,7 +10,14 @@ class RefreshSitemapWorker
|
||||
|
||||
if redis.set(lock_key, Time.current.to_s, nx: true, ex: lock_ttl)
|
||||
begin
|
||||
generate_sitemap
|
||||
setup_sitemap_config
|
||||
# 生成默认的不带语言前缀的 sitemap
|
||||
generate_sitemap(nil)
|
||||
|
||||
# 为每个可用语言生成带前缀的 sitemap
|
||||
I18n.available_locales.each do |locale|
|
||||
generate_sitemap(locale)
|
||||
end
|
||||
ensure
|
||||
redis.del(lock_key)
|
||||
end
|
||||
@ -21,10 +28,11 @@ class RefreshSitemapWorker
|
||||
|
||||
private
|
||||
|
||||
def generate_sitemap
|
||||
host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000"
|
||||
Rails.application.routes.default_url_options[:host] = host
|
||||
SitemapGenerator::Sitemap.default_host = ENV.fetch("RAILS_SITEMAP_DEFAULT_HOST", host)
|
||||
def setup_sitemap_config
|
||||
@host = Rails.env.production? ? "https://todayaiweather.com" : "http://127.0.0.1:3000"
|
||||
Rails.application.routes.default_url_options[:host] = @host
|
||||
SitemapGenerator::Sitemap.default_host = ENV.fetch("RAILS_SITEMAP_DEFAULT_HOST", @host)
|
||||
|
||||
if Rails.env.production?
|
||||
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AwsSdkAdapter.new(
|
||||
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)),
|
||||
@ -45,36 +53,77 @@ class RefreshSitemapWorker
|
||||
)
|
||||
end
|
||||
SitemapGenerator::Sitemap.sitemaps_path = "sitemaps/"
|
||||
end
|
||||
|
||||
SitemapGenerator::Sitemap.create do
|
||||
add root_path, changefreq: "daily", priority: 1.0
|
||||
add cities_path, changefreq: "daily", priority: 0.9
|
||||
add arts_path, changefreq: "daily", priority: 0.9
|
||||
def generate_sitemap(locale = nil)
|
||||
# 设置当前语言环境
|
||||
I18n.locale = locale || I18n.default_locale
|
||||
Rails.application.routes.default_url_options[:locale] = locale
|
||||
|
||||
# 设置 sitemap 路径
|
||||
# path_prefix = locale ? "sitemaps/#{locale}/" : "sitemaps/"
|
||||
# SitemapGenerator::Sitemap.sitemaps_path = path_prefix
|
||||
|
||||
filename = locale==nil ? "sitemap" : "sitemap_#{locale}"
|
||||
SitemapGenerator::Sitemap.create(filename: filename) do
|
||||
available_locales = I18n.available_locales
|
||||
|
||||
# 首页
|
||||
add root_path(locale: locale),
|
||||
changefreq: "daily",
|
||||
priority: 1.0,
|
||||
alternate: available_locales.map { |al|
|
||||
{ lang: al, href: root_url(locale: al) }
|
||||
}
|
||||
|
||||
# 城市列表页
|
||||
add cities_path(locale: locale),
|
||||
changefreq: "daily",
|
||||
priority: 0.9,
|
||||
alternate: available_locales.map { |al|
|
||||
{ lang: al, href: cities_url(locale: al) }
|
||||
}
|
||||
|
||||
# 艺术作品列表页
|
||||
add arts_path(locale: locale),
|
||||
changefreq: "daily",
|
||||
priority: 0.9,
|
||||
alternate: available_locales.map { |al|
|
||||
{ lang: al, href: arts_url(locale: al) }
|
||||
}
|
||||
|
||||
# 城市详情页
|
||||
City.find_each do |city|
|
||||
add city_path(city),
|
||||
add city_path(city, locale: locale),
|
||||
changefreq: "daily",
|
||||
priority: 0.8,
|
||||
lastmod: city.updated_at
|
||||
lastmod: city.updated_at,
|
||||
alternate: available_locales.map { |al|
|
||||
{ lang: al, href: city_url(city, locale: al) }
|
||||
}
|
||||
end
|
||||
|
||||
# 天气艺术作品页
|
||||
WeatherArt.includes(:city).find_each do |art|
|
||||
if art.image.attached?
|
||||
add city_weather_art_path(art.city, art),
|
||||
add city_weather_art_path(art.city, art, locale: locale),
|
||||
changefreq: "daily",
|
||||
priority: 0.7,
|
||||
lastmod: art.updated_at,
|
||||
images: [ {
|
||||
loc: url_for(art.image),
|
||||
title: "#{art.city.name} Weather Art - #{art.weather_date.strftime('%B %d, %Y')}"
|
||||
} ]
|
||||
loc: url_for(art.image),
|
||||
title: "#{art.city.name} Weather Art - #{art.weather_date.strftime('%B %d, %Y')}"
|
||||
} ],
|
||||
alternate: available_locales.map { |al|
|
||||
{ lang: al, href: city_weather_art_url(art.city, art, locale: al) }
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# SitemapGenerator::Sitemap.ping_search_engines if Rails.env.production?
|
||||
Rails.logger.info "Sitemap has been generated and uploaded to S3 successfully"
|
||||
Rails.logger.info "Generated sitemap for #{locale || 'default'} version"
|
||||
rescue => e
|
||||
Rails.logger.error "Error refreshing sitemap: #{e.message}"
|
||||
Rails.logger.error "Error generating sitemap for #{locale || 'default'}: #{e.message}"
|
||||
raise e
|
||||
end
|
||||
end
|
||||
|
19
config/initializers/locale.rb
Normal file
19
config/initializers/locale.rb
Normal file
@ -0,0 +1,19 @@
|
||||
# config/initializers/locale.rb
|
||||
require "i18n/backend/fallbacks"
|
||||
|
||||
# Where the I18n library should search for translation files
|
||||
I18n.load_path += Dir[Rails.root.join("config", "locales", "*.{rb,yml}")]
|
||||
|
||||
# Permitted locales available for the application
|
||||
I18n.available_locales = [ :en, :"zh-CN", :ja, :ko, :"pt-BR", :hr, :fa, :de, :es, :fr, :it, :tr, :ru, :uk, :pl, :bn, :hi, :ur, :ar ]
|
||||
|
||||
I18n::Backend::Simple.send(:include, I18n::Backend::Fallbacks)
|
||||
# I18n::Backend::Simple.include I18n::Backend::Fallbacks
|
||||
# I18n.fallbacks[:en]
|
||||
I18n.fallbacks = I18n::Locale::Fallbacks.new(
|
||||
en: [ :en ],
|
||||
'zh-CN': [ :zh, :zh_cn, :en ]
|
||||
)
|
||||
|
||||
# Set default locale to something other than :en
|
||||
I18n.default_locale = :en
|
67
config/locales/ar.yml
Normal file
67
config/locales/ar.yml
Normal file
@ -0,0 +1,67 @@
|
||||
ar:
|
||||
hello: "مرحباً بالعالم"
|
||||
brand:
|
||||
name: "الطقس اليوم بالذكاء الاصطناعي"
|
||||
title:
|
||||
cities: "المدن"
|
||||
arts: "الفنون"
|
||||
sign_in: "تسجيل الدخول"
|
||||
sign_out: "تسجيل الخروج"
|
||||
settings: "الإعدادات"
|
||||
admin_dashboard: "لوحة تحكم المشرف"
|
||||
latest_weather_art: "أحدث فن الطقس"
|
||||
popular_weather_art: "فن الطقس الشائع"
|
||||
ai_prompt: "موجه الذكاء الاصطناعي"
|
||||
text:
|
||||
latest_from: "أحدث من"
|
||||
search_cities: "البحث عن المدن..."
|
||||
all_regions: "جميع المناطق"
|
||||
all_countries: "جميع البلدان"
|
||||
all_in: "الكل في"
|
||||
showing: "عرض"
|
||||
weather_arts: "فنون الطقس"
|
||||
newest_first: "الأحدث أولاً"
|
||||
oldest_first: "الأقدم أولاً"
|
||||
cities:
|
||||
title: "استكشف المدن"
|
||||
arts:
|
||||
title: "معرض فنون الطقس"
|
||||
subtitle: "اكتشف فن الطقس المُنشأ بالذكاء الاصطناعي من مدن حول العالم"
|
||||
home:
|
||||
headline_html: حيث يلتقي الطقس<br>بالذكاء الاصطناعي
|
||||
subtitle:
|
||||
اختبر الطقس من خلال عدسة الفن المُنشأ بالذكاء الاصطناعي،
|
||||
مما يجلب منظوراً جديداً للظواهر الجوية اليومية.
|
||||
button:
|
||||
explore_cities: "استكشف المدن"
|
||||
view_detail: "عرض التفاصيل"
|
||||
view_all_weather_arts: "عرض كل فنون الطقس"
|
||||
back_to_cities: "العودة إلى المدن"
|
||||
back_to: "العودة إلى"
|
||||
card:
|
||||
temperature: "درجة الحرارة"
|
||||
wind: "الرياح"
|
||||
humidity: "الرطوبة"
|
||||
visibility: "الرؤية"
|
||||
pressure: "الضغط"
|
||||
cloud_cover: "الغطاء السحابي"
|
||||
feel_like: "الشعور كأنها"
|
||||
relative_humidity: "الرطوبة النسبية"
|
||||
clear_view_distance: "مسافة الرؤية الواضحة"
|
||||
atmospheric_pressure: "الضغط الجوي"
|
||||
sky_coverage: "تغطية السماء"
|
||||
pagination:
|
||||
showing_items: "عرض %{from} إلى %{to} من %{total} %{items}"
|
||||
items:
|
||||
weather: "سجلات الطقس"
|
||||
default: "العناصر"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
67
config/locales/bn.yml
Normal file
67
config/locales/bn.yml
Normal file
@ -0,0 +1,67 @@
|
||||
bn:
|
||||
hello: "ওহে বিশ্ব"
|
||||
brand:
|
||||
name: "টুডে এআই ওয়েদার"
|
||||
title:
|
||||
cities: "শহরগুলি"
|
||||
arts: "শিল্প"
|
||||
sign_in: "সাইন ইন"
|
||||
sign_out: "সাইন আউট"
|
||||
settings: "সেটিংস"
|
||||
admin_dashboard: "অ্যাডমিন ড্যাশবোর্ড"
|
||||
latest_weather_art: "সর্বশেষ আবহাওয়া শিল্প"
|
||||
popular_weather_art: "জনপ্রিয় আবহাওয়া শিল্প"
|
||||
ai_prompt: "এআই প্রম্পট"
|
||||
text:
|
||||
latest_from: "সর্বশেষ"
|
||||
search_cities: "শহর অনুসন্ধান..."
|
||||
all_regions: "সব অঞ্চল"
|
||||
all_countries: "সব দেশ"
|
||||
all_in: "সবগুলি"
|
||||
showing: "দেখাচ্ছে"
|
||||
weather_arts: "আবহাওয়া শিল্প"
|
||||
newest_first: "নতুনগুলি প্রথমে"
|
||||
oldest_first: "পুরানোগুলি প্রথমে"
|
||||
cities:
|
||||
title: "শহরগুলি অন্বেষণ করুন"
|
||||
arts:
|
||||
title: "আবহাওয়া শিল্প গ্যালারি"
|
||||
subtitle: "বিশ্বজুড়ে শহরগুলি থেকে এআই-জেনারেটেড আবহাওয়া শিল্প আবিষ্কার করুন"
|
||||
home:
|
||||
headline_html: যেখানে আবহাওয়া মিলিত হয়<br>কৃত্রিম বুদ্ধিমত্তার সাথে
|
||||
subtitle:
|
||||
এআই-জেনারেটেড শিল্পের মাধ্যমে আবহাওয়া অনুভব করুন,
|
||||
দৈনিক আবহাওয়া ঘটনার একটি নতুন দৃষ্টিভঙ্গি আনয়ন করে।
|
||||
button:
|
||||
explore_cities: "শহরগুলি অন্বেষণ করুন"
|
||||
view_detail: "বিস্তারিত দেখুন"
|
||||
view_all_weather_arts: "সমস্ত আবহাওয়া শিল্প দেখুন"
|
||||
back_to_cities: "শহরগুলিতে ফিরে যান"
|
||||
back_to: "ফিরে যান"
|
||||
card:
|
||||
temperature: "তাপমাত্রা"
|
||||
wind: "বাতাস"
|
||||
humidity: "আর্দ্রতা"
|
||||
visibility: "দৃশ্যমানতা"
|
||||
pressure: "চাপ"
|
||||
cloud_cover: "মেঘাচ্ছন্নতা"
|
||||
feel_like: "অনুভূত হয়"
|
||||
relative_humidity: "আপেক্ষিক আর্দ্রতা"
|
||||
clear_view_distance: "পরিষ্কার দৃষ্টির দূরত্ব"
|
||||
atmospheric_pressure: "বায়ুমণ্ডলীয় চাপ"
|
||||
sky_coverage: "আকাশ আচ্ছাদন"
|
||||
pagination:
|
||||
showing_items: "%{total} %{items}-এর মধ্যে %{from} থেকে %{to} দেখানো হচ্ছে"
|
||||
items:
|
||||
weather: "আবহাওয়া রেকর্ড"
|
||||
default: "আইটেম"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
@ -1,55 +0,0 @@
|
||||
en:
|
||||
countries:
|
||||
# East Asia
|
||||
CN: 'China'
|
||||
JP: 'Japan'
|
||||
KR: 'South Korea'
|
||||
TW: 'Taiwan'
|
||||
HK: 'Hong Kong'
|
||||
|
||||
# South Asia
|
||||
IN: 'India'
|
||||
PK: 'Pakistan'
|
||||
BD: 'Bangladesh'
|
||||
|
||||
# Southeast Asia
|
||||
ID: 'Indonesia'
|
||||
VN: 'Vietnam'
|
||||
TH: 'Thailand'
|
||||
MM: 'Myanmar'
|
||||
SG: 'Singapore'
|
||||
|
||||
# Middle East
|
||||
TR: 'Turkey'
|
||||
IR: 'Iran'
|
||||
SA: 'Saudi Arabia'
|
||||
IQ: 'Iraq'
|
||||
|
||||
# Africa
|
||||
NG: 'Nigeria'
|
||||
EG: 'Egypt'
|
||||
CD: 'Democratic Republic of the Congo'
|
||||
TZ: 'Tanzania'
|
||||
ZA: 'South Africa'
|
||||
KE: 'Kenya'
|
||||
AO: 'Angola'
|
||||
ML: 'Mali'
|
||||
CI: 'Ivory Coast'
|
||||
|
||||
# Europe
|
||||
RU: 'Russia'
|
||||
GB: 'United Kingdom'
|
||||
DE: 'Germany'
|
||||
|
||||
# North America
|
||||
US: 'United States'
|
||||
MX: 'Mexico'
|
||||
|
||||
# South America
|
||||
BR: 'Brazil'
|
||||
PE: 'Peru'
|
||||
CO: 'Colombia'
|
||||
CL: 'Chile'
|
||||
|
||||
# Oceania
|
||||
AU: 'Australia'
|
@ -1,55 +0,0 @@
|
||||
zh-CN:
|
||||
countries:
|
||||
# East Asia
|
||||
CN: '中国'
|
||||
JP: '日本'
|
||||
KR: '韩国'
|
||||
TW: '台湾'
|
||||
HK: '香港'
|
||||
|
||||
# South Asia
|
||||
IN: '印度'
|
||||
PK: '巴基斯坦'
|
||||
BD: '孟加拉国'
|
||||
|
||||
# Southeast Asia
|
||||
ID: '印度尼西亚'
|
||||
VN: '越南'
|
||||
TH: '泰国'
|
||||
MM: '缅甸'
|
||||
SG: '新加坡'
|
||||
|
||||
# Middle East
|
||||
TR: '土耳其'
|
||||
IR: '伊朗'
|
||||
SA: '沙特阿拉伯'
|
||||
IQ: '伊拉克'
|
||||
|
||||
# Africa
|
||||
NG: '尼日利亚'
|
||||
EG: '埃及'
|
||||
CD: '刚果民主共和国'
|
||||
TZ: '坦桑尼亚'
|
||||
ZA: '南非'
|
||||
KE: '肯尼亚'
|
||||
AO: '安哥拉'
|
||||
ML: '马里'
|
||||
CI: '科特迪瓦'
|
||||
|
||||
# Europe
|
||||
RU: '俄罗斯'
|
||||
GB: '英国'
|
||||
DE: '德国'
|
||||
|
||||
# North America
|
||||
US: '美国'
|
||||
MX: '墨西哥'
|
||||
|
||||
# South America
|
||||
BR: '巴西'
|
||||
PE: '秘鲁'
|
||||
CO: '哥伦比亚'
|
||||
CL: '智利'
|
||||
|
||||
# Oceania
|
||||
AU: '澳大利亚'
|
67
config/locales/de.yml
Normal file
67
config/locales/de.yml
Normal file
@ -0,0 +1,67 @@
|
||||
de:
|
||||
hello: "Hallo Welt"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Städte"
|
||||
arts: "Kunst"
|
||||
sign_in: "Anmelden"
|
||||
sign_out: "Abmelden"
|
||||
settings: "Einstellungen"
|
||||
admin_dashboard: "Admin-Dashboard"
|
||||
latest_weather_art: "Neueste Wetterkunst"
|
||||
popular_weather_art: "Beliebte Wetterkunst"
|
||||
ai_prompt: "KI-Prompt"
|
||||
text:
|
||||
latest_from: "Neuestes von"
|
||||
search_cities: "Städte suchen..."
|
||||
all_regions: "Alle Regionen"
|
||||
all_countries: "Alle Länder"
|
||||
all_in: "Alles in"
|
||||
showing: "Zeigt"
|
||||
weather_arts: "Wetterkunst"
|
||||
newest_first: "Neueste zuerst"
|
||||
oldest_first: "Älteste zuerst"
|
||||
cities:
|
||||
title: "Städte erkunden"
|
||||
arts:
|
||||
title: "Wetterkunst-Galerie"
|
||||
subtitle: "Entdecken Sie KI-generierte Wetterkunst aus Städten auf der ganzen Welt"
|
||||
home:
|
||||
headline_html: Wo Wetter auf<br>Künstliche Intelligenz trifft
|
||||
subtitle:
|
||||
Erleben Sie Wetter durch die Linse KI-generierter Kunst,
|
||||
die eine neue Perspektive auf tägliche meteorologische Phänomene bietet.
|
||||
button:
|
||||
explore_cities: "Städte erkunden"
|
||||
view_detail: "Details anzeigen"
|
||||
view_all_weather_arts: "Alle Wetterkunst anzeigen"
|
||||
back_to_cities: "Zurück zu Städten"
|
||||
back_to: "Zurück zu"
|
||||
card:
|
||||
temperature: "Temperatur"
|
||||
wind: "Wind"
|
||||
humidity: "Luftfeuchtigkeit"
|
||||
visibility: "Sichtweite"
|
||||
pressure: "Luftdruck"
|
||||
cloud_cover: "Bewölkung"
|
||||
feel_like: "Gefühlt wie"
|
||||
relative_humidity: "Relative Luftfeuchtigkeit"
|
||||
clear_view_distance: "Klare Sichtweite"
|
||||
atmospheric_pressure: "Atmosphärischer Druck"
|
||||
sky_coverage: "Himmelsbedeckung"
|
||||
pagination:
|
||||
showing_items: "Zeigt %{from} bis %{to} von %{total} %{items}"
|
||||
items:
|
||||
weather: "Wetteraufzeichnungen"
|
||||
default: "Einträge"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%d. %b"
|
||||
long: "%d. %B %Y"
|
@ -28,4 +28,90 @@
|
||||
# enabled: "ON"
|
||||
|
||||
en:
|
||||
hello: "Hello world"
|
||||
language:
|
||||
en: "English"
|
||||
zh-CN: "简体中文"
|
||||
ja: "日本語"
|
||||
ko: "한국어" # 韩语
|
||||
pt-BR: "Português (Brasil)" # 巴西葡萄牙语
|
||||
pt: "Português" # 葡萄牙语
|
||||
hr: "Hrvatski" # 克罗地亚语
|
||||
fa: "فارسی" # 波斯语(法尔西语)
|
||||
de: "Deutsch" # 德语
|
||||
es: "Español" # 西班牙语
|
||||
fr: "Français" # 法语
|
||||
it: "Italiano" # 意大利语
|
||||
tr: "Türkçe" # 土耳其语
|
||||
ru: "Русский" # 俄语
|
||||
uk: "Українська" # 乌克兰语
|
||||
pl: "Polski" # 波兰语
|
||||
bn: "বাংলা" # 孟加拉
|
||||
hi: "हिंदी" # 印地语
|
||||
ur: " اردو" # 乌尔都语
|
||||
ar: "العربية" # 阿拉伯
|
||||
hello: "Hello world"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Cities"
|
||||
arts: "Arts"
|
||||
sign_in: "Sign in"
|
||||
sign_out: "Sign out"
|
||||
settings: "Settings"
|
||||
admin_dashboard: "Admin Dashboard"
|
||||
latest_weather_art: "Latest Weather Art"
|
||||
popular_weather_art: "Popular Weather Art"
|
||||
ai_prompt: "AI Prompt"
|
||||
text:
|
||||
latest_from: "Latest from"
|
||||
search_cities: "Search cities..."
|
||||
all_regions: "All Regions"
|
||||
all_countries: "All Countries"
|
||||
all_in: "All in"
|
||||
showing: "Showing"
|
||||
weather_arts: "Weather Arts"
|
||||
newest_first: "Newest First"
|
||||
oldest_first: "Oldest First"
|
||||
cities:
|
||||
title: "Explore Cities"
|
||||
arts:
|
||||
title: "Weather Arts Gallery"
|
||||
subtitle: "Discover AI-generated weather art from cities around the world"
|
||||
home:
|
||||
headline_html: Where Weather Meets<br>Artificial Intelligence
|
||||
subtitle:
|
||||
Experience weather through the lens of AI-generated art,
|
||||
bringing a new perspective to daily meteorological phenomena.
|
||||
button:
|
||||
explore_cities: "Explore Cities"
|
||||
view_detail: "View Details"
|
||||
view_all_weather_arts: "View All Weather Arts"
|
||||
back_to_cities: "Back to Cities"
|
||||
back_to: "Back to"
|
||||
card:
|
||||
temperature: "Temperature"
|
||||
wind: "Wind"
|
||||
humidity: "Humidity"
|
||||
visibility: "Visibility"
|
||||
pressure: "Pressure"
|
||||
cloud_cover: "Cloud Cover"
|
||||
feel_like: "Feels like"
|
||||
relative_humidity: "Relative humidity"
|
||||
clear_view_distance: "Clear view distance"
|
||||
atmospheric_pressure: "Atmospheric pressure"
|
||||
sky_coverage: "Sky coverage"
|
||||
pagination:
|
||||
showing_items: "Showing %{from} to %{to} of %{total} %{items}"
|
||||
items:
|
||||
weather: "weather records"
|
||||
default: "items"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
||||
|
67
config/locales/es.yml
Normal file
67
config/locales/es.yml
Normal file
@ -0,0 +1,67 @@
|
||||
es:
|
||||
hello: "Hola mundo"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Ciudades"
|
||||
arts: "Arte"
|
||||
sign_in: "Iniciar sesión"
|
||||
sign_out: "Cerrar sesión"
|
||||
settings: "Configuración"
|
||||
admin_dashboard: "Panel de administración"
|
||||
latest_weather_art: "Último arte del tiempo"
|
||||
popular_weather_art: "Arte del tiempo popular"
|
||||
ai_prompt: "Prompt de IA"
|
||||
text:
|
||||
latest_from: "Lo último de"
|
||||
search_cities: "Buscar ciudades..."
|
||||
all_regions: "Todas las regiones"
|
||||
all_countries: "Todos los países"
|
||||
all_in: "Todo en"
|
||||
showing: "Mostrando"
|
||||
weather_arts: "Arte del tiempo"
|
||||
newest_first: "Más recientes primero"
|
||||
oldest_first: "Más antiguos primero"
|
||||
cities:
|
||||
title: "Explorar ciudades"
|
||||
arts:
|
||||
title: "Galería de arte del tiempo"
|
||||
subtitle: "Descubre arte generado por IA del tiempo de ciudades de todo el mundo"
|
||||
home:
|
||||
headline_html: Donde el tiempo se encuentra<br>con la Inteligencia Artificial
|
||||
subtitle:
|
||||
Experimenta el tiempo a través del lente del arte generado por IA,
|
||||
brindando una nueva perspectiva a los fenómenos meteorológicos diarios.
|
||||
button:
|
||||
explore_cities: "Explorar ciudades"
|
||||
view_detail: "Ver detalles"
|
||||
view_all_weather_arts: "Ver todo el arte del tiempo"
|
||||
back_to_cities: "Volver a ciudades"
|
||||
back_to: "Volver a"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Viento"
|
||||
humidity: "Humedad"
|
||||
visibility: "Visibilidad"
|
||||
pressure: "Presión"
|
||||
cloud_cover: "Cobertura de nubes"
|
||||
feel_like: "Sensación térmica"
|
||||
relative_humidity: "Humedad relativa"
|
||||
clear_view_distance: "Distancia de visibilidad clara"
|
||||
atmospheric_pressure: "Presión atmosférica"
|
||||
sky_coverage: "Cobertura del cielo"
|
||||
pagination:
|
||||
showing_items: "Mostrando %{from} a %{to} de %{total} %{items}"
|
||||
items:
|
||||
weather: "registros meteorológicos"
|
||||
default: "elementos"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d de %B de %Y"
|
67
config/locales/fa.yml
Normal file
67
config/locales/fa.yml
Normal file
@ -0,0 +1,67 @@
|
||||
fa:
|
||||
hello: "سلام دنیا"
|
||||
brand:
|
||||
name: "هوای هوش مصنوعی امروز"
|
||||
title:
|
||||
cities: "شهرها"
|
||||
arts: "هنرها"
|
||||
sign_in: "ورود"
|
||||
sign_out: "خروج"
|
||||
settings: "تنظیمات"
|
||||
admin_dashboard: "داشبورد مدیر"
|
||||
latest_weather_art: "آخرین هنر آب و هوا"
|
||||
popular_weather_art: "هنر آب و هوای محبوب"
|
||||
ai_prompt: "پرامپت هوش مصنوعی"
|
||||
text:
|
||||
latest_from: "آخرین از"
|
||||
search_cities: "جستجوی شهرها..."
|
||||
all_regions: "همه مناطق"
|
||||
all_countries: "همه کشورها"
|
||||
all_in: "همه در"
|
||||
showing: "نمایش"
|
||||
weather_arts: "هنرهای آب و هوا"
|
||||
newest_first: "جدیدترین اول"
|
||||
oldest_first: "قدیمیترین اول"
|
||||
cities:
|
||||
title: "کاوش شهرها"
|
||||
arts:
|
||||
title: "گالری هنرهای آب و هوا"
|
||||
subtitle: "کشف هنر آب و هوای تولید شده توسط هوش مصنوعی از شهرهای سراسر جهان"
|
||||
home:
|
||||
headline_html: جایی که آب و هوا با<br>هوش مصنوعی ملاقات میکند
|
||||
subtitle:
|
||||
تجربه آب و هوا از طریق لنز هنر تولید شده توسط هوش مصنوعی،
|
||||
آوردن دیدگاهی جدید به پدیدههای هواشناسی روزانه.
|
||||
button:
|
||||
explore_cities: "کاوش شهرها"
|
||||
view_detail: "مشاهده جزئیات"
|
||||
view_all_weather_arts: "مشاهده همه هنرهای آب و هوا"
|
||||
back_to_cities: "بازگشت به شهرها"
|
||||
back_to: "بازگشت به"
|
||||
card:
|
||||
temperature: "دما"
|
||||
wind: "باد"
|
||||
humidity: "رطوبت"
|
||||
visibility: "دید"
|
||||
pressure: "فشار"
|
||||
cloud_cover: "پوشش ابر"
|
||||
feel_like: "احساس مانند"
|
||||
relative_humidity: "رطوبت نسبی"
|
||||
clear_view_distance: "فاصله دید شفاف"
|
||||
atmospheric_pressure: "فشار جو"
|
||||
sky_coverage: "پوشش آسمان"
|
||||
pagination:
|
||||
showing_items: "نمایش %{from} تا %{to} از %{total} %{items}"
|
||||
items:
|
||||
weather: "رکوردهای آب و هوا"
|
||||
default: "موارد"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
67
config/locales/fr.yml
Normal file
67
config/locales/fr.yml
Normal file
@ -0,0 +1,67 @@
|
||||
fr:
|
||||
hello: "Bonjour le monde"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Villes"
|
||||
arts: "Arts"
|
||||
sign_in: "Se connecter"
|
||||
sign_out: "Se déconnecter"
|
||||
settings: "Paramètres"
|
||||
admin_dashboard: "Tableau de bord administrateur"
|
||||
latest_weather_art: "Derniers arts météorologiques"
|
||||
popular_weather_art: "Arts météorologiques populaires"
|
||||
ai_prompt: "Prompt IA"
|
||||
text:
|
||||
latest_from: "Derniers de"
|
||||
search_cities: "Rechercher des villes..."
|
||||
all_regions: "Toutes les régions"
|
||||
all_countries: "Tous les pays"
|
||||
all_in: "Tout dans"
|
||||
showing: "Affichage"
|
||||
weather_arts: "Arts météorologiques"
|
||||
newest_first: "Plus récents d'abord"
|
||||
oldest_first: "Plus anciens d'abord"
|
||||
cities:
|
||||
title: "Explorer les villes"
|
||||
arts:
|
||||
title: "Galerie d'arts météorologiques"
|
||||
subtitle: "Découvrez l'art météorologique généré par l'IA des villes du monde entier"
|
||||
home:
|
||||
headline_html: "Là où la météo rencontre<br>l'Intelligence Artificielle"
|
||||
subtitle:
|
||||
Découvrez la météo à travers le prisme de l'art généré par l'IA,
|
||||
apportant une nouvelle perspective aux phénomènes météorologiques quotidiens.
|
||||
button:
|
||||
explore_cities: "Explorer les villes"
|
||||
view_detail: "Voir les détails"
|
||||
view_all_weather_arts: "Voir tous les arts météorologiques"
|
||||
back_to_cities: "Retour aux villes"
|
||||
back_to: "Retour à"
|
||||
card:
|
||||
temperature: "Température"
|
||||
wind: "Vent"
|
||||
humidity: "Humidité"
|
||||
visibility: "Visibilité"
|
||||
pressure: "Pression"
|
||||
cloud_cover: "Couverture nuageuse"
|
||||
feel_like: "Ressenti"
|
||||
relative_humidity: "Humidité relative"
|
||||
clear_view_distance: "Distance de visibilité claire"
|
||||
atmospheric_pressure: "Pression atmosphérique"
|
||||
sky_coverage: "Couverture du ciel"
|
||||
pagination:
|
||||
showing_items: "Affichage de %{from} à %{to} sur %{total} %{items}"
|
||||
items:
|
||||
weather: "relevés météorologiques"
|
||||
default: "éléments"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d %B %Y"
|
67
config/locales/hi.yml
Normal file
67
config/locales/hi.yml
Normal file
@ -0,0 +1,67 @@
|
||||
hi:
|
||||
hello: "नमस्ते दुनिया"
|
||||
brand:
|
||||
name: "टुडे एआई वेदर"
|
||||
title:
|
||||
cities: "शहर"
|
||||
arts: "कला"
|
||||
sign_in: "साइन इन"
|
||||
sign_out: "साइन आउट"
|
||||
settings: "सेटिंग्स"
|
||||
admin_dashboard: "एडमिन डैशबोर्ड"
|
||||
latest_weather_art: "नवीनतम मौसम कला"
|
||||
popular_weather_art: "लोकप्रिय मौसम कला"
|
||||
ai_prompt: "एआई प्रॉम्प्ट"
|
||||
text:
|
||||
latest_from: "से नवीनतम"
|
||||
search_cities: "शहर खोजें..."
|
||||
all_regions: "सभी क्षेत्र"
|
||||
all_countries: "सभी देश"
|
||||
all_in: "सभी में"
|
||||
showing: "दिखा रहा है"
|
||||
weather_arts: "मौसम कला"
|
||||
newest_first: "नवीनतम पहले"
|
||||
oldest_first: "सबसे पुराना पहले"
|
||||
cities:
|
||||
title: "शहरों की खोज करें"
|
||||
arts:
|
||||
title: "मौसम कला गैलरी"
|
||||
subtitle: "दुनिया भर के शहरों से एआई-जनित मौसम कला की खोज करें"
|
||||
home:
|
||||
headline_html: जहां मौसम मिलता है<br>कृत्रिम बुद्धिमत्ता
|
||||
subtitle:
|
||||
एआई-जनित कला के माध्यम से मौसम का अनुभव करें,
|
||||
दैनिक मौसम संबंधी घटनाओं को एक नया दृष्टिकोण प्रदान करें।
|
||||
button:
|
||||
explore_cities: "शहरों की खोज करें"
|
||||
view_detail: "विवरण देखें"
|
||||
view_all_weather_arts: "सभी मौसम कला देखें"
|
||||
back_to_cities: "शहरों पर वापस जाएं"
|
||||
back_to: "वापस जाएं"
|
||||
card:
|
||||
temperature: "तापमान"
|
||||
wind: "हवा"
|
||||
humidity: "नमी"
|
||||
visibility: "दृश्यता"
|
||||
pressure: "दबाव"
|
||||
cloud_cover: "बादल छाए"
|
||||
feel_like: "महसूस होता है"
|
||||
relative_humidity: "सापेक्ष आर्द्रता"
|
||||
clear_view_distance: "स्पष्ट दृश्य दूरी"
|
||||
atmospheric_pressure: "वायुमंडलीय दबाव"
|
||||
sky_coverage: "आकाश कवरेज"
|
||||
pagination:
|
||||
showing_items: "%{total} %{items} में से %{from} से %{to} तक दिखा रहा है"
|
||||
items:
|
||||
weather: "मौसम रिकॉर्ड"
|
||||
default: "आइटम"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
67
config/locales/hr.yml
Normal file
67
config/locales/hr.yml
Normal file
@ -0,0 +1,67 @@
|
||||
hr:
|
||||
hello: "Pozdrav svijete"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Gradovi"
|
||||
arts: "Umjetnost"
|
||||
sign_in: "Prijava"
|
||||
sign_out: "Odjava"
|
||||
settings: "Postavke"
|
||||
admin_dashboard: "Administratorska ploča"
|
||||
latest_weather_art: "Najnovija vremenska umjetnost"
|
||||
popular_weather_art: "Popularna vremenska umjetnost"
|
||||
ai_prompt: "AI upit"
|
||||
text:
|
||||
latest_from: "Najnovije od"
|
||||
search_cities: "Pretraži gradove..."
|
||||
all_regions: "Sve regije"
|
||||
all_countries: "Sve države"
|
||||
all_in: "Sve u"
|
||||
showing: "Prikazuje se"
|
||||
weather_arts: "Vremenska umjetnost"
|
||||
newest_first: "Najnovije prvo"
|
||||
oldest_first: "Najstarije prvo"
|
||||
cities:
|
||||
title: "Istražite gradove"
|
||||
arts:
|
||||
title: "Galerija vremenske umjetnosti"
|
||||
subtitle: "Otkrijte umjetnost vremena generiranu AI-em iz gradova širom svijeta"
|
||||
home:
|
||||
headline_html: Gdje se vrijeme susreće<br>s umjetnom inteligencijom
|
||||
subtitle:
|
||||
Doživite vrijeme kroz objektiv umjetnosti generirane AI-em,
|
||||
donoseći novu perspektivu svakodnevnim meteorološkim pojavama.
|
||||
button:
|
||||
explore_cities: "Istražite gradove"
|
||||
view_detail: "Pogledaj detalje"
|
||||
view_all_weather_arts: "Pogledaj svu vremensku umjetnost"
|
||||
back_to_cities: "Natrag na gradove"
|
||||
back_to: "Natrag na"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Vjetar"
|
||||
humidity: "Vlažnost"
|
||||
visibility: "Vidljivost"
|
||||
pressure: "Tlak"
|
||||
cloud_cover: "Naoblaka"
|
||||
feel_like: "Osjeća se kao"
|
||||
relative_humidity: "Relativna vlažnost"
|
||||
clear_view_distance: "Udaljenost čistog pogleda"
|
||||
atmospheric_pressure: "Atmosferski tlak"
|
||||
sky_coverage: "Pokrivenost neba"
|
||||
pagination:
|
||||
showing_items: "Prikazuje se %{from} do %{to} od %{total} %{items}"
|
||||
items:
|
||||
weather: "vremenskih zapisa"
|
||||
default: "stavki"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d. %B %Y."
|
67
config/locales/it.yml
Normal file
67
config/locales/it.yml
Normal file
@ -0,0 +1,67 @@
|
||||
it:
|
||||
hello: "Ciao mondo"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Città"
|
||||
arts: "Arte"
|
||||
sign_in: "Accedi"
|
||||
sign_out: "Esci"
|
||||
settings: "Impostazioni"
|
||||
admin_dashboard: "Dashboard Amministratore"
|
||||
latest_weather_art: "Ultima Arte Meteorologica"
|
||||
popular_weather_art: "Arte Meteorologica Popolare"
|
||||
ai_prompt: "Prompt IA"
|
||||
text:
|
||||
latest_from: "Ultimi da"
|
||||
search_cities: "Cerca città..."
|
||||
all_regions: "Tutte le Regioni"
|
||||
all_countries: "Tutti i Paesi"
|
||||
all_in: "Tutto in"
|
||||
showing: "Mostrando"
|
||||
weather_arts: "Arte Meteorologica"
|
||||
newest_first: "Prima i più Recenti"
|
||||
oldest_first: "Prima i più Vecchi"
|
||||
cities:
|
||||
title: "Esplora Città"
|
||||
arts:
|
||||
title: "Galleria Arte Meteorologica"
|
||||
subtitle: "Scopri l'arte meteorologica generata dall'IA dalle città di tutto il mondo"
|
||||
home:
|
||||
headline_html: Dove il Meteo Incontra<br>l'Intelligenza Artificiale
|
||||
subtitle:
|
||||
Vivi il meteo attraverso la lente dell'arte generata dall'IA,
|
||||
portando una nuova prospettiva ai fenomeni meteorologici quotidiani.
|
||||
button:
|
||||
explore_cities: "Esplora Città"
|
||||
view_detail: "Visualizza Dettagli"
|
||||
view_all_weather_arts: "Visualizza Tutta l'Arte Meteorologica"
|
||||
back_to_cities: "Torna alle Città"
|
||||
back_to: "Torna a"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Vento"
|
||||
humidity: "Umidità"
|
||||
visibility: "Visibilità"
|
||||
pressure: "Pressione"
|
||||
cloud_cover: "Copertura Nuvolosa"
|
||||
feel_like: "Percepita"
|
||||
relative_humidity: "Umidità relativa"
|
||||
clear_view_distance: "Distanza di visibilità"
|
||||
atmospheric_pressure: "Pressione atmosferica"
|
||||
sky_coverage: "Copertura del cielo"
|
||||
pagination:
|
||||
showing_items: "Mostrando da %{from} a %{to} di %{total} %{items}"
|
||||
items:
|
||||
weather: "registrazioni meteo"
|
||||
default: "elementi"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d %B %Y"
|
66
config/locales/ja.yml
Normal file
66
config/locales/ja.yml
Normal file
@ -0,0 +1,66 @@
|
||||
ja:
|
||||
hello: "こんにちは世界"
|
||||
brand:
|
||||
name: "今日のAI天気"
|
||||
title:
|
||||
cities: "都市"
|
||||
arts: "アート"
|
||||
sign_in: "サインイン"
|
||||
sign_out: "サインアウト"
|
||||
settings: "設定"
|
||||
admin_dashboard: "管理者ダッシュボード"
|
||||
latest_weather_art: "最新の天気アート"
|
||||
popular_weather_art: "人気の天気アート"
|
||||
ai_prompt: "AIプロンプト"
|
||||
text:
|
||||
latest_from: "最新情報"
|
||||
search_cities: "都市を検索..."
|
||||
all_regions: "すべての地域"
|
||||
all_countries: "すべての国"
|
||||
all_in: "すべて含む"
|
||||
showing: "表示中"
|
||||
weather_arts: "天気アート"
|
||||
newest_first: "最新順"
|
||||
oldest_first: "古い順"
|
||||
cities:
|
||||
title: "都市を探る"
|
||||
arts:
|
||||
title: "天気アートギャラリー"
|
||||
subtitle: "世界中の都市から生成されたAI天気アートを発見"
|
||||
home:
|
||||
headline_html: 天気が出会う場所<br>人工知能
|
||||
subtitle:
|
||||
AI生成アートのレンズを通して天気を体験し、
|
||||
日常の気象現象に新しい視点をもたらします。
|
||||
button:
|
||||
explore_cities: "都市を探る"
|
||||
view_detail: "詳細を見る"
|
||||
view_all_weather_arts: "すべての天気アートを見る"
|
||||
back_to_cities: "都市に戻る"
|
||||
back_to: "戻る"
|
||||
card:
|
||||
temperature: "温度"
|
||||
wind: "風"
|
||||
humidity: "湿度"
|
||||
visibility: "視界"
|
||||
pressure: "圧力"
|
||||
cloud_cover: "雲の覆い"
|
||||
feel_like: "体感温度"
|
||||
relative_humidity: "相対湿度"
|
||||
clear_view_distance: "クリアビュー距離"
|
||||
atmospheric_pressure: "大気圧"
|
||||
sky_coverage: "空の覆い"
|
||||
pagination:
|
||||
showing_items: "合計 %{total} %{items} のうち %{from} から %{to} まで表示"
|
||||
items:
|
||||
weather: "天気記録"
|
||||
default: "アイテム"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
short: "%Y-%m-%d"
|
||||
long: "%Y 年 %m 月 %d 日"
|
66
config/locales/ko.yml
Normal file
66
config/locales/ko.yml
Normal file
@ -0,0 +1,66 @@
|
||||
ko:
|
||||
hello: "안녕하세요 세계"
|
||||
brand:
|
||||
name: "오늘의 AI 날씨"
|
||||
title:
|
||||
cities: "도시"
|
||||
arts: "예술"
|
||||
sign_in: "로그인"
|
||||
sign_out: "로그아웃"
|
||||
settings: "설정"
|
||||
admin_dashboard: "관리자 대시보드"
|
||||
latest_weather_art: "최신 날씨 예술"
|
||||
popular_weather_art: "인기 있는 날씨 예술"
|
||||
ai_prompt: "AI 프롬프트"
|
||||
text:
|
||||
latest_from: "최신 소식"
|
||||
search_cities: "도시 검색..."
|
||||
all_regions: "모든 지역"
|
||||
all_countries: "모든 국가"
|
||||
all_in: "모두 포함"
|
||||
showing: "표시 중"
|
||||
weather_arts: "날씨 예술"
|
||||
newest_first: "최신순"
|
||||
oldest_first: "오래된 순"
|
||||
cities:
|
||||
title: "도시 탐험"
|
||||
arts:
|
||||
title: "날씨 예술 갤러리"
|
||||
subtitle: "전 세계 도시에서 생성된 AI 날씨 예술 발견하기"
|
||||
home:
|
||||
headline_html: 날씨가 만나는 곳<br>인공지능
|
||||
subtitle:
|
||||
AI 생성 예술의 렌즈를 통해 날씨를 경험하세요,
|
||||
일상적인 기상 현상에 대한 새로운 관점을 제공합니다.
|
||||
button:
|
||||
explore_cities: "도시 탐험"
|
||||
view_detail: "상세 보기"
|
||||
view_all_weather_arts: "모든 날씨 예술 보기"
|
||||
back_to_cities: "도시로 돌아가기"
|
||||
back_to: "돌아가기"
|
||||
card:
|
||||
temperature: "온도"
|
||||
wind: "바람"
|
||||
humidity: "습도"
|
||||
visibility: "가시성"
|
||||
pressure: "압력"
|
||||
cloud_cover: "구름 덮개"
|
||||
feel_like: "체감 온도"
|
||||
relative_humidity: "상대 습도"
|
||||
clear_view_distance: "맑은 시야 거리"
|
||||
atmospheric_pressure: "대기압"
|
||||
sky_coverage: "하늘 덮개"
|
||||
pagination:
|
||||
showing_items: "총 %{total} %{items} 중 %{from}에서 %{to}까지 표시"
|
||||
items:
|
||||
weather: "날씨 기록"
|
||||
default: "항목"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
short: "%Y-%m-%d"
|
||||
long: "%Y 년 %m 월 %d 일"
|
67
config/locales/pl.yml
Normal file
67
config/locales/pl.yml
Normal file
@ -0,0 +1,67 @@
|
||||
pl:
|
||||
hello: "Witaj świecie"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Miasta"
|
||||
arts: "Sztuka"
|
||||
sign_in: "Zaloguj się"
|
||||
sign_out: "Wyloguj się"
|
||||
settings: "Ustawienia"
|
||||
admin_dashboard: "Panel administratora"
|
||||
latest_weather_art: "Najnowsza sztuka pogodowa"
|
||||
popular_weather_art: "Popularna sztuka pogodowa"
|
||||
ai_prompt: "Prompt AI"
|
||||
text:
|
||||
latest_from: "Najnowsze z"
|
||||
search_cities: "Szukaj miast..."
|
||||
all_regions: "Wszystkie regiony"
|
||||
all_countries: "Wszystkie kraje"
|
||||
all_in: "Wszystko w"
|
||||
showing: "Wyświetlanie"
|
||||
weather_arts: "Sztuka pogodowa"
|
||||
newest_first: "Od najnowszych"
|
||||
oldest_first: "Od najstarszych"
|
||||
cities:
|
||||
title: "Odkryj miasta"
|
||||
arts:
|
||||
title: "Galeria sztuki pogodowej"
|
||||
subtitle: "Odkryj sztukę pogodową generowaną przez AI z miast na całym świecie"
|
||||
home:
|
||||
headline_html: Gdzie pogoda spotyka się<br>ze sztuczną inteligencją
|
||||
subtitle:
|
||||
Doświadcz pogody przez pryzmat sztuki generowanej przez AI,
|
||||
wprowadzając nową perspektywę do codziennych zjawisk meteorologicznych.
|
||||
button:
|
||||
explore_cities: "Odkryj miasta"
|
||||
view_detail: "Zobacz szczegóły"
|
||||
view_all_weather_arts: "Zobacz całą sztukę pogodową"
|
||||
back_to_cities: "Powrót do miast"
|
||||
back_to: "Powrót do"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Wiatr"
|
||||
humidity: "Wilgotność"
|
||||
visibility: "Widoczność"
|
||||
pressure: "Ciśnienie"
|
||||
cloud_cover: "Zachmurzenie"
|
||||
feel_like: "Odczuwalna"
|
||||
relative_humidity: "Wilgotność względna"
|
||||
clear_view_distance: "Zasięg widoczności"
|
||||
atmospheric_pressure: "Ciśnienie atmosferyczne"
|
||||
sky_coverage: "Pokrycie nieba"
|
||||
pagination:
|
||||
showing_items: "Wyświetlanie %{from} do %{to} z %{total} %{items}"
|
||||
items:
|
||||
weather: "zapisów pogody"
|
||||
default: "elementów"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d %B %Y"
|
67
config/locales/pt-BR.yml
Normal file
67
config/locales/pt-BR.yml
Normal file
@ -0,0 +1,67 @@
|
||||
pt-BR:
|
||||
hello: "Olá mundo"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Cidades"
|
||||
arts: "Artes"
|
||||
sign_in: "Entrar"
|
||||
sign_out: "Sair"
|
||||
settings: "Configurações"
|
||||
admin_dashboard: "Painel de Administração"
|
||||
latest_weather_art: "Arte Meteorológica Mais Recente"
|
||||
popular_weather_art: "Arte Meteorológica Popular"
|
||||
ai_prompt: "Prompt de IA"
|
||||
text:
|
||||
latest_from: "Mais recente de"
|
||||
search_cities: "Pesquisar cidades..."
|
||||
all_regions: "Todas as Regiões"
|
||||
all_countries: "Todos os Países"
|
||||
all_in: "Tudo em"
|
||||
showing: "Mostrando"
|
||||
weather_arts: "Artes Meteorológicas"
|
||||
newest_first: "Mais Recentes Primeiro"
|
||||
oldest_first: "Mais Antigos Primeiro"
|
||||
cities:
|
||||
title: "Explorar Cidades"
|
||||
arts:
|
||||
title: "Galeria de Artes Meteorológicas"
|
||||
subtitle: "Descubra arte meteorológica gerada por IA de cidades ao redor do mundo"
|
||||
home:
|
||||
headline_html: Onde o Clima Encontra<br>a Inteligência Artificial
|
||||
subtitle:
|
||||
Experimente o clima através das lentes da arte gerada por IA,
|
||||
trazendo uma nova perspectiva para os fenômenos meteorológicos diários.
|
||||
button:
|
||||
explore_cities: "Explorar Cidades"
|
||||
view_detail: "Ver Detalhes"
|
||||
view_all_weather_arts: "Ver Todas as Artes Meteorológicas"
|
||||
back_to_cities: "Voltar para Cidades"
|
||||
back_to: "Voltar para"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Vento"
|
||||
humidity: "Umidade"
|
||||
visibility: "Visibilidade"
|
||||
pressure: "Pressão"
|
||||
cloud_cover: "Cobertura de Nuvens"
|
||||
feel_like: "Sensação térmica"
|
||||
relative_humidity: "Umidade relativa"
|
||||
clear_view_distance: "Distância de visão clara"
|
||||
atmospheric_pressure: "Pressão atmosférica"
|
||||
sky_coverage: "Cobertura do céu"
|
||||
pagination:
|
||||
showing_items: "Mostrando %{from} até %{to} de %{total} %{items}"
|
||||
items:
|
||||
weather: "registros meteorológicos"
|
||||
default: "itens"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%d/%m/%Y"
|
||||
short: "%d %b"
|
||||
long: "%d de %B de %Y"
|
67
config/locales/pt.yml
Normal file
67
config/locales/pt.yml
Normal file
@ -0,0 +1,67 @@
|
||||
pt:
|
||||
hello: "Olá mundo"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Cidades"
|
||||
arts: "Artes"
|
||||
sign_in: "Entrar"
|
||||
sign_out: "Sair"
|
||||
settings: "Configurações"
|
||||
admin_dashboard: "Painel de Administração"
|
||||
latest_weather_art: "Arte Meteorológica Mais Recente"
|
||||
popular_weather_art: "Arte Meteorológica Popular"
|
||||
ai_prompt: "Prompt de IA"
|
||||
text:
|
||||
latest_from: "Mais recente de"
|
||||
search_cities: "Pesquisar cidades..."
|
||||
all_regions: "Todas as Regiões"
|
||||
all_countries: "Todos os Países"
|
||||
all_in: "Tudo em"
|
||||
showing: "Mostrando"
|
||||
weather_arts: "Artes Meteorológicas"
|
||||
newest_first: "Mais Recentes Primeiro"
|
||||
oldest_first: "Mais Antigos Primeiro"
|
||||
cities:
|
||||
title: "Explorar Cidades"
|
||||
arts:
|
||||
title: "Galeria de Artes Meteorológicas"
|
||||
subtitle: "Descubra arte meteorológica gerada por IA de cidades ao redor do mundo"
|
||||
home:
|
||||
headline_html: Onde o Clima Encontra<br>a Inteligência Artificial
|
||||
subtitle:
|
||||
Experimente o clima através das lentes da arte gerada por IA,
|
||||
trazendo uma nova perspectiva para os fenômenos meteorológicos diários.
|
||||
button:
|
||||
explore_cities: "Explorar Cidades"
|
||||
view_detail: "Ver Detalhes"
|
||||
view_all_weather_arts: "Ver Todas as Artes Meteorológicas"
|
||||
back_to_cities: "Voltar para Cidades"
|
||||
back_to: "Voltar para"
|
||||
card:
|
||||
temperature: "Temperatura"
|
||||
wind: "Vento"
|
||||
humidity: "Umidade"
|
||||
visibility: "Visibilidade"
|
||||
pressure: "Pressão"
|
||||
cloud_cover: "Cobertura de Nuvens"
|
||||
feel_like: "Sensação térmica"
|
||||
relative_humidity: "Umidade relativa"
|
||||
clear_view_distance: "Distância de visão clara"
|
||||
atmospheric_pressure: "Pressão atmosférica"
|
||||
sky_coverage: "Cobertura do céu"
|
||||
pagination:
|
||||
showing_items: "Mostrando %{from} a %{to} de %{total} %{items}"
|
||||
items:
|
||||
weather: "registros meteorológicos"
|
||||
default: "itens"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%d de %b"
|
||||
long: "%d de %B de %Y"
|
@ -1,15 +0,0 @@
|
||||
en:
|
||||
regions:
|
||||
AS: 'Asia'
|
||||
SA: 'South Asia'
|
||||
SEA: 'Southeast Asia'
|
||||
EA: 'East Asia'
|
||||
ME: 'Middle East'
|
||||
AF: 'Africa'
|
||||
NA: 'North Africa'
|
||||
SSA: 'Sub-Saharan Africa'
|
||||
EU: 'Europe'
|
||||
NAM: 'North America'
|
||||
SAM: 'South America'
|
||||
CAM: 'Central America'
|
||||
OC: 'Oceania'
|
@ -1,15 +0,0 @@
|
||||
zh-CN:
|
||||
regions:
|
||||
AS: '亚洲'
|
||||
SA: '南亚'
|
||||
SEA: '东南亚'
|
||||
EA: '东亚'
|
||||
ME: '中东'
|
||||
AF: '非洲'
|
||||
NA: '北非'
|
||||
SSA: '撒哈拉以南非洲'
|
||||
EU: '欧洲'
|
||||
NAM: '北美洲'
|
||||
SAM: '南美洲'
|
||||
CAM: '中美洲'
|
||||
OC: '大洋洲'
|
67
config/locales/ru.yml
Normal file
67
config/locales/ru.yml
Normal file
@ -0,0 +1,67 @@
|
||||
ru:
|
||||
hello: "Привет, мир"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Города"
|
||||
arts: "Искусство"
|
||||
sign_in: "Войти"
|
||||
sign_out: "Выйти"
|
||||
settings: "Настройки"
|
||||
admin_dashboard: "Панель администратора"
|
||||
latest_weather_art: "Последнее погодное искусство"
|
||||
popular_weather_art: "Популярное погодное искусство"
|
||||
ai_prompt: "AI подсказка"
|
||||
text:
|
||||
latest_from: "Последнее от"
|
||||
search_cities: "Поиск городов..."
|
||||
all_regions: "Все регионы"
|
||||
all_countries: "Все страны"
|
||||
all_in: "Все в"
|
||||
showing: "Показано"
|
||||
weather_arts: "Погодное искусство"
|
||||
newest_first: "Сначала новые"
|
||||
oldest_first: "Сначала старые"
|
||||
cities:
|
||||
title: "Исследуйте города"
|
||||
arts:
|
||||
title: "Галерея погодного искусства"
|
||||
subtitle: "Откройте для себя AI-сгенерированное погодное искусство из городов по всему миру"
|
||||
home:
|
||||
headline_html: Где погода встречается<br>с искусственным интеллектом
|
||||
subtitle:
|
||||
Познакомьтесь с погодой через призму искусства, созданного искусственным интеллектом,
|
||||
открывая новый взгляд на ежедневные метеорологические явления.
|
||||
button:
|
||||
explore_cities: "Исследовать города"
|
||||
view_detail: "Посмотреть детали"
|
||||
view_all_weather_arts: "Посмотреть все погодное искусство"
|
||||
back_to_cities: "Вернуться к городам"
|
||||
back_to: "Вернуться к"
|
||||
card:
|
||||
temperature: "Температура"
|
||||
wind: "Ветер"
|
||||
humidity: "Влажность"
|
||||
visibility: "Видимость"
|
||||
pressure: "Давление"
|
||||
cloud_cover: "Облачность"
|
||||
feel_like: "Ощущается как"
|
||||
relative_humidity: "Относительная влажность"
|
||||
clear_view_distance: "Дальность видимости"
|
||||
atmospheric_pressure: "Атмосферное давление"
|
||||
sky_coverage: "Покрытие неба"
|
||||
pagination:
|
||||
showing_items: "Показано с %{from} по %{to} из %{total} %{items}"
|
||||
items:
|
||||
weather: "записей о погоде"
|
||||
default: "элементов"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d %B %Y"
|
67
config/locales/tr.yml
Normal file
67
config/locales/tr.yml
Normal file
@ -0,0 +1,67 @@
|
||||
tr:
|
||||
hello: "Merhaba dünya"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Şehirler"
|
||||
arts: "Sanat"
|
||||
sign_in: "Giriş yap"
|
||||
sign_out: "Çıkış yap"
|
||||
settings: "Ayarlar"
|
||||
admin_dashboard: "Yönetici Paneli"
|
||||
latest_weather_art: "En Son Hava Durumu Sanatı"
|
||||
popular_weather_art: "Popüler Hava Durumu Sanatı"
|
||||
ai_prompt: "AI Komut"
|
||||
text:
|
||||
latest_from: "En son"
|
||||
search_cities: "Şehirleri ara..."
|
||||
all_regions: "Tüm Bölgeler"
|
||||
all_countries: "Tüm Ülkeler"
|
||||
all_in: "Tümü"
|
||||
showing: "Gösteriliyor"
|
||||
weather_arts: "Hava Durumu Sanatları"
|
||||
newest_first: "En Yeni Önce"
|
||||
oldest_first: "En Eski Önce"
|
||||
cities:
|
||||
title: "Şehirleri Keşfet"
|
||||
arts:
|
||||
title: "Hava Durumu Sanat Galerisi"
|
||||
subtitle: "Dünya genelindeki şehirlerden AI tarafından oluşturulan hava durumu sanatını keşfedin"
|
||||
home:
|
||||
headline_html: "Hava Durumu<br>Yapay Zeka ile Buluşuyor"
|
||||
subtitle:
|
||||
AI tarafından oluşturulan sanat perspektifinden hava durumunu deneyimleyin,
|
||||
günlük meteorolojik olaylara yeni bir bakış açısı getirin.
|
||||
button:
|
||||
explore_cities: "Şehirleri Keşfet"
|
||||
view_detail: "Detayları Görüntüle"
|
||||
view_all_weather_arts: "Tüm Hava Durumu Sanatlarını Görüntüle"
|
||||
back_to_cities: "Şehirlere Geri Dön"
|
||||
back_to: "Geri Dön"
|
||||
card:
|
||||
temperature: "Sıcaklık"
|
||||
wind: "Rüzgar"
|
||||
humidity: "Nem"
|
||||
visibility: "Görüş Mesafesi"
|
||||
pressure: "Basınç"
|
||||
cloud_cover: "Bulut Örtüsü"
|
||||
feel_like: "Hissedilen"
|
||||
relative_humidity: "Bağıl nem"
|
||||
clear_view_distance: "Net görüş mesafesi"
|
||||
atmospheric_pressure: "Atmosfer basıncı"
|
||||
sky_coverage: "Gökyüzü kapsama"
|
||||
pagination:
|
||||
showing_items: "%{total} %{items} içinden %{from} ile %{to} arası gösteriliyor"
|
||||
items:
|
||||
weather: "hava durumu kayıtları"
|
||||
default: "öğe"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%d %b"
|
||||
long: "%d %B %Y"
|
67
config/locales/uk.yml
Normal file
67
config/locales/uk.yml
Normal file
@ -0,0 +1,67 @@
|
||||
uk:
|
||||
hello: "Привіт світ"
|
||||
brand:
|
||||
name: "Today AI Weather"
|
||||
title:
|
||||
cities: "Міста"
|
||||
arts: "Мистецтво"
|
||||
sign_in: "Увійти"
|
||||
sign_out: "Вийти"
|
||||
settings: "Налаштування"
|
||||
admin_dashboard: "Панель адміністратора"
|
||||
latest_weather_art: "Останнє погодне мистецтво"
|
||||
popular_weather_art: "Популярне погодне мистецтво"
|
||||
ai_prompt: "AI підказка"
|
||||
text:
|
||||
latest_from: "Останнє від"
|
||||
search_cities: "Пошук міст..."
|
||||
all_regions: "Всі регіони"
|
||||
all_countries: "Всі країни"
|
||||
all_in: "Все в"
|
||||
showing: "Показано"
|
||||
weather_arts: "Погодне мистецтво"
|
||||
newest_first: "Спочатку нові"
|
||||
oldest_first: "Спочатку старі"
|
||||
cities:
|
||||
title: "Огляд міст"
|
||||
arts:
|
||||
title: "Галерея погодного мистецтва"
|
||||
subtitle: "Відкрийте для себе згенероване ШІ погодне мистецтво з міст по всьому світу"
|
||||
home:
|
||||
headline_html: Де погода зустрічається<br>зі штучним інтелектом
|
||||
subtitle:
|
||||
Відчуйте погоду через призму мистецтва, створеного ШІ,
|
||||
що дає новий погляд на щоденні метеорологічні явища.
|
||||
button:
|
||||
explore_cities: "Огляд міст"
|
||||
view_detail: "Переглянути деталі"
|
||||
view_all_weather_arts: "Переглянути все погодне мистецтво"
|
||||
back_to_cities: "Назад до міст"
|
||||
back_to: "Назад до"
|
||||
card:
|
||||
temperature: "Температура"
|
||||
wind: "Вітер"
|
||||
humidity: "Вологість"
|
||||
visibility: "Видимість"
|
||||
pressure: "Тиск"
|
||||
cloud_cover: "Хмарність"
|
||||
feel_like: "Відчувається як"
|
||||
relative_humidity: "Відносна вологість"
|
||||
clear_view_distance: "Дальність видимості"
|
||||
atmospheric_pressure: "Атмосферний тиск"
|
||||
sky_coverage: "Покриття неба"
|
||||
pagination:
|
||||
showing_items: "Показано %{from} до %{to} з %{total} %{items}"
|
||||
items:
|
||||
weather: "погодних записів"
|
||||
default: "елементів"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%d %B %Y"
|
67
config/locales/ur.yml
Normal file
67
config/locales/ur.yml
Normal file
@ -0,0 +1,67 @@
|
||||
ur:
|
||||
hello: "ہیلو دنیا"
|
||||
brand:
|
||||
name: "ٹوڈے اے آئی ویدر"
|
||||
title:
|
||||
cities: "شہر"
|
||||
arts: "فن"
|
||||
sign_in: "سائن ان"
|
||||
sign_out: "سائن آؤٹ"
|
||||
settings: "ترتیبات"
|
||||
admin_dashboard: "ایڈمن ڈیش بورڈ"
|
||||
latest_weather_art: "تازہ ترین موسمی فن"
|
||||
popular_weather_art: "مقبول موسمی فن"
|
||||
ai_prompt: "اے آئی پرامپٹ"
|
||||
text:
|
||||
latest_from: "تازہ ترین"
|
||||
search_cities: "شہروں کی تلاش..."
|
||||
all_regions: "تمام علاقے"
|
||||
all_countries: "تمام ممالک"
|
||||
all_in: "تمام"
|
||||
showing: "دکھا رہا ہے"
|
||||
weather_arts: "موسمی فن"
|
||||
newest_first: "نیا پہلے"
|
||||
oldest_first: "پرانا پہلے"
|
||||
cities:
|
||||
title: "شہروں کی دریافت"
|
||||
arts:
|
||||
title: "موسمی فن گیلری"
|
||||
subtitle: "دنیا بھر کے شہروں سے اے آئی سے تیار کردہ موسمی فن دریافت کریں"
|
||||
home:
|
||||
headline_html: جہاں موسم<br>مصنوعی ذہانت سے ملتا ہے
|
||||
subtitle:
|
||||
اے آئی سے تیار کردہ فن کے ذریعے موسم کا تجربہ کریں،
|
||||
روزمرہ موسمیاتی مظاہر کو ایک نیا نظریہ فراہم کرتا ہے۔
|
||||
button:
|
||||
explore_cities: "شہروں کی دریافت"
|
||||
view_detail: "تفصیلات دیکھیں"
|
||||
view_all_weather_arts: "تمام موسمی فن دیکھیں"
|
||||
back_to_cities: "شہروں کی طرف واپس"
|
||||
back_to: "واپس"
|
||||
card:
|
||||
temperature: "درجہ حرارت"
|
||||
wind: "ہوا"
|
||||
humidity: "نمی"
|
||||
visibility: "دید"
|
||||
pressure: "دباؤ"
|
||||
cloud_cover: "بادل"
|
||||
feel_like: "محسوس ہوتا ہے"
|
||||
relative_humidity: "اضافی نمی"
|
||||
clear_view_distance: "صاف نظر کی دوری"
|
||||
atmospheric_pressure: "ہوائی دباؤ"
|
||||
sky_coverage: "آسمانی احاطہ"
|
||||
pagination:
|
||||
showing_items: "%{items} کے %{total} میں سے %{from} سے %{to} تک دکھا رہا ہے"
|
||||
items:
|
||||
weather: "موسمی ریکارڈز"
|
||||
default: "آئٹمز"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
default: "%Y-%m-%d"
|
||||
short: "%b %d"
|
||||
long: "%B %d, %Y"
|
65
config/locales/zh-CN.yml
Normal file
65
config/locales/zh-CN.yml
Normal file
@ -0,0 +1,65 @@
|
||||
zh-CN:
|
||||
hello: "你好"
|
||||
brand:
|
||||
name: "全球艺术天气"
|
||||
title:
|
||||
cities: "城市探索"
|
||||
arts: "艺术巡览"
|
||||
sign_in: "用户登录"
|
||||
sign_out: "退出登录"
|
||||
settings: "系统设置"
|
||||
admin_dashboard: "管理中枢"
|
||||
latest_weather_art: "气象绘卷·新作"
|
||||
popular_weather_art: "气象绘卷·佳作"
|
||||
ai_prompt: "天气描述"
|
||||
text:
|
||||
latest_from: "新至之城"
|
||||
search_cities: "寻城觅境…"
|
||||
all_regions: "寰宇之境"
|
||||
all_countries: "所有国家"
|
||||
all_in: "全部"
|
||||
showing: "映现"
|
||||
weather_arts: "气象艺境"
|
||||
newest_first: "最新优先"
|
||||
oldest_first: "最早优先"
|
||||
cities:
|
||||
title: "云游四海"
|
||||
arts:
|
||||
title: "天象画廊"
|
||||
subtitle: "邂逅寰宇都市AI气象绘卷"
|
||||
home:
|
||||
headline_html: 当气象邂逅<br>人工智能之美
|
||||
subtitle:
|
||||
通过AI生成的艺术视角感受气象,为日常天气现象带来全新解读。
|
||||
button:
|
||||
explore_cities: "云游四海"
|
||||
view_detail: "详阅此卷"
|
||||
view_all_weather_arts: "尽览天工"
|
||||
back_to_cities: "继续探索城市"
|
||||
back_to: "回到"
|
||||
card:
|
||||
temperature: "温度"
|
||||
wind: "风力"
|
||||
humidity: "湿度"
|
||||
visibility: "能见度"
|
||||
pressure: "气压"
|
||||
cloud_cover: "云量"
|
||||
feel_like: "体感温度"
|
||||
relative_humidity: "相对湿度"
|
||||
clear_view_distance: "清晰视距"
|
||||
atmospheric_pressure: "大气压力"
|
||||
sky_coverage: "天空覆盖"
|
||||
pagination:
|
||||
showing_items: "显示第 %{from} 到第 %{to} 条,共 %{total} 条%{items}"
|
||||
items:
|
||||
weather: "天气记录"
|
||||
default: "记录"
|
||||
time:
|
||||
formats:
|
||||
time_only: "%H:%M"
|
||||
with_zone: "%{time} %{zone}"
|
||||
date_and_time: "%{date} %{time}"
|
||||
date:
|
||||
formats:
|
||||
short: "%Y-%m-%d"
|
||||
long: "%Y 年 %m 月 %d 日"
|
@ -1,49 +1,53 @@
|
||||
require "sidekiq/web"
|
||||
|
||||
Rails.application.routes.draw do
|
||||
devise_for :users
|
||||
root "home#index"
|
||||
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
|
||||
devise_for :users
|
||||
root "home#index"
|
||||
|
||||
resources :cities, only: [ :index, :show ] do
|
||||
resources :weather_arts, path: "weather", only: [ :show ], param: :slug
|
||||
end
|
||||
resources :cities do
|
||||
member do
|
||||
post :generate_weather_art, param: :slug
|
||||
resources :cities, only: [ :index, :show ] do
|
||||
resources :weather_arts, path: "weather", only: [ :show ], param: :slug
|
||||
end
|
||||
resources :cities do
|
||||
member do
|
||||
post :generate_weather_art, param: :slug
|
||||
end
|
||||
end
|
||||
resources :arts, only: [ :index ]
|
||||
|
||||
# namespace :admin do
|
||||
# resources :cities
|
||||
# resources :weather_arts
|
||||
# root to: "cities#index"
|
||||
# end
|
||||
|
||||
get "weather_arts/show"
|
||||
get "cities/index"
|
||||
get "cities/show"
|
||||
get "home/index"
|
||||
get "sitemaps", to: "sitemaps#index"
|
||||
get "sitemaps/*path", to: "sitemaps#show", format: false
|
||||
get "feed", to: "rss#feed", format: "rss", as: :rss_feed
|
||||
|
||||
devise_for :admin_users, ActiveAdmin::Devise.config
|
||||
ActiveAdmin.routes(self)
|
||||
|
||||
# mount Sidekiq::Web => '/sidekiq'
|
||||
# authenticate :admin_user do
|
||||
authenticate :user, lambda { |u| u.admin? } do
|
||||
mount Sidekiq::Web => "/admin/tasks"
|
||||
end
|
||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||
|
||||
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
||||
# Can be used by load balancers and uptime monitors to verify that the app is live.
|
||||
get "up" => "rails/health#show", as: :rails_health_check
|
||||
|
||||
# Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb)
|
||||
# get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
|
||||
# get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker
|
||||
|
||||
# Defines the root path route ("/")
|
||||
# root "posts#index"
|
||||
end
|
||||
resources :arts, only: [ :index ]
|
||||
|
||||
# namespace :admin do
|
||||
# resources :cities
|
||||
# resources :weather_arts
|
||||
# root to: "cities#index"
|
||||
# end
|
||||
|
||||
get "weather_arts/show"
|
||||
get "cities/index"
|
||||
get "cities/show"
|
||||
get "home/index"
|
||||
get "sitemaps/*path", to: "sitemaps#show", format: false
|
||||
|
||||
devise_for :admin_users, ActiveAdmin::Devise.config
|
||||
ActiveAdmin.routes(self)
|
||||
|
||||
# mount Sidekiq::Web => '/sidekiq'
|
||||
# authenticate :admin_user do
|
||||
authenticate :user, lambda { |u| u.admin? } do
|
||||
mount Sidekiq::Web => "/admin/tasks"
|
||||
end
|
||||
# Define your application routes per the DSL in https://guides.rubyonrails.org/routing.html
|
||||
|
||||
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
|
||||
# Can be used by load balancers and uptime monitors to verify that the app is live.
|
||||
get "up" => "rails/health#show", as: :rails_health_check
|
||||
|
||||
# Render dynamic PWA files from app/views/pwa/* (remember to link manifest in application.html.erb)
|
||||
# get "manifest" => "rails/pwa#manifest", as: :pwa_manifest
|
||||
# get "service-worker" => "rails/pwa#service_worker", as: :pwa_service_worker
|
||||
|
||||
# Defines the root path route ("/")
|
||||
# root "posts#index"
|
||||
end
|
||||
|
40
db/seeds.rb
40
db/seeds.rb
@ -10,11 +10,6 @@
|
||||
# AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password') if Rails.env.development?
|
||||
AdminUser.create!(email: 'admin@example.com', password: 'password', password_confirmation: 'password')
|
||||
|
||||
# WeatherArt.delete_all
|
||||
# City.delete_all
|
||||
# Country.delete_all
|
||||
# Region.delete_all
|
||||
|
||||
# 创建区域
|
||||
regions = Region.create!([
|
||||
{
|
||||
@ -22,46 +17,14 @@ regions = Region.create!([
|
||||
code: 'AS'
|
||||
# },
|
||||
# {
|
||||
# name: 'Southeast Asia',
|
||||
# code: 'SEA'
|
||||
# },
|
||||
# {
|
||||
# name: 'East Asia',
|
||||
# code: 'EA'
|
||||
# },
|
||||
# {
|
||||
# name: 'Middle East',
|
||||
# code: 'ME'
|
||||
# },
|
||||
# {
|
||||
# name: 'Africa',
|
||||
# code: 'AF'
|
||||
# },
|
||||
# {
|
||||
# name: 'North Africa',
|
||||
# code: 'NA'
|
||||
# },
|
||||
# {
|
||||
# name: 'Sub-Saharan Africa',
|
||||
# code: 'SSA'
|
||||
# },
|
||||
# {
|
||||
# name: 'Europe',
|
||||
# code: 'EU'
|
||||
# },
|
||||
# {
|
||||
# name: 'North America',
|
||||
# code: 'NAM'
|
||||
# },
|
||||
# {
|
||||
# name: 'South America',
|
||||
# code: 'SAM'
|
||||
# },
|
||||
# {
|
||||
# name: 'Central America',
|
||||
# code: 'CAM'
|
||||
# },
|
||||
# {
|
||||
# name: 'Oceania',
|
||||
# code: 'OC'
|
||||
}
|
||||
@ -133,9 +96,6 @@ Country.create!([
|
||||
])
|
||||
|
||||
# 创建城市
|
||||
# Dir[Rails.root.join('db/seeds/cities/*.rb')].sort.each do |file|
|
||||
# require file
|
||||
# end
|
||||
china = Country.find_by code: 'CN'
|
||||
City.create!([
|
||||
{
|
||||
|
@ -1,22 +0,0 @@
|
||||
australia = Country.find_by code: 'AU'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Sydney',
|
||||
latitude: -33.8688,
|
||||
longitude: 151.2093,
|
||||
country: australia,
|
||||
timezone: 'Australia/Sydney',
|
||||
active: true,
|
||||
priority: 80
|
||||
},
|
||||
{
|
||||
name: 'Melbourne',
|
||||
latitude: -37.8136,
|
||||
longitude: 144.9631,
|
||||
country: australia,
|
||||
timezone: 'Australia/Melbourne',
|
||||
active: true,
|
||||
priority: 75
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
bangladesh = Country.find_by code: 'BD'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Dhaka',
|
||||
latitude: 23.8103,
|
||||
longitude: 90.4125,
|
||||
country: bangladesh,
|
||||
timezone: 'Asia/Dhaka',
|
||||
active: true,
|
||||
priority: 85
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
brazil = Country.find_by code: 'BR'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Rio de Janeiro',
|
||||
latitude: -22.9068,
|
||||
longitude: -43.1729,
|
||||
country: brazil,
|
||||
timezone: 'America/Sao_Paulo',
|
||||
active: true,
|
||||
priority: 80
|
||||
}
|
||||
])
|
@ -1,10 +0,0 @@
|
||||
canada = Country.find_by code: 'CA'
|
||||
City.create!(
|
||||
name: 'Toronto',
|
||||
latitude: 43.6532,
|
||||
longitude: -79.3832,
|
||||
priority: 50,
|
||||
country: canada,
|
||||
timezone: 'America/Toronto',
|
||||
active: true
|
||||
)
|
@ -1,346 +0,0 @@
|
||||
china = Country.find_by code: 'CN'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Shanghai',
|
||||
latitude: 31.2304,
|
||||
longitude: 121.4737,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Beijing',
|
||||
latitude: 39.9042,
|
||||
longitude: 116.4074,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Shenzhen',
|
||||
latitude: 22.5431,
|
||||
longitude: 114.0579,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Guangzhou',
|
||||
latitude: 23.1291,
|
||||
longitude: 113.2644,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Chengdu',
|
||||
latitude: 30.5728,
|
||||
longitude: 104.0668,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Tianjin',
|
||||
latitude: 39.3434,
|
||||
longitude: 117.3616,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Wuhan',
|
||||
latitude: 30.5928,
|
||||
longitude: 114.3055,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Dongguan',
|
||||
latitude: 23.0208,
|
||||
longitude: 113.7518,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Chongqing',
|
||||
latitude: 29.4316,
|
||||
longitude: 106.9123,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: "Xi'an",
|
||||
latitude: 34.3416,
|
||||
longitude: 108.9398,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Hangzhou',
|
||||
latitude: 30.2741,
|
||||
longitude: 120.1551,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Foshan',
|
||||
latitude: 23.0219,
|
||||
longitude: 113.1216,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Nanjing',
|
||||
latitude: 32.0603,
|
||||
longitude: 118.7969,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Hong Kong',
|
||||
latitude: 22.3193,
|
||||
longitude: 114.1694,
|
||||
country: china,
|
||||
timezone: 'Asia/Hong_Kong',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Shenyang',
|
||||
latitude: 41.8057,
|
||||
longitude: 123.4315,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Zhengzhou',
|
||||
latitude: 34.7472,
|
||||
longitude: 113.6249,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Qingdao',
|
||||
latitude: 36.0671,
|
||||
longitude: 120.3826,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Suzhou',
|
||||
latitude: 31.2990,
|
||||
longitude: 120.5853,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Changsha',
|
||||
latitude: 28.2282,
|
||||
longitude: 112.9388,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Jinan',
|
||||
latitude: 36.6512,
|
||||
longitude: 117.1201,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Kunming',
|
||||
latitude: 25.0389,
|
||||
longitude: 102.7183,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Harbin',
|
||||
latitude: 45.8038,
|
||||
longitude: 126.5340,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Shijiazhuang',
|
||||
latitude: 38.0428,
|
||||
longitude: 114.5149,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Hefei',
|
||||
latitude: 31.8206,
|
||||
longitude: 117.2272,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Dalian',
|
||||
latitude: 38.9140,
|
||||
longitude: 121.6147,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Xiamen',
|
||||
latitude: 24.4798,
|
||||
longitude: 118.0819,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Nanning',
|
||||
latitude: 22.8170,
|
||||
longitude: 108.3665,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Changchun',
|
||||
latitude: 43.8171,
|
||||
longitude: 125.3235,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Taiyuan',
|
||||
latitude: 37.8706,
|
||||
longitude: 112.5489,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'New Taipei City',
|
||||
latitude: 25.0120,
|
||||
longitude: 121.4657,
|
||||
country: china,
|
||||
timezone: 'Asia/Taipei',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Guiyang',
|
||||
latitude: 26.6470,
|
||||
longitude: 106.6302,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Wuxi',
|
||||
latitude: 31.4914,
|
||||
longitude: 120.3119,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Shantou',
|
||||
latitude: 23.3535,
|
||||
longitude: 116.6822,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Ürümqi',
|
||||
latitude: 43.8256,
|
||||
longitude: 87.6168,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Zhongshan',
|
||||
latitude: 22.5415,
|
||||
longitude: 113.3926,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Ningbo',
|
||||
latitude: 29.8683,
|
||||
longitude: 121.5440,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Fuzhou',
|
||||
latitude: 26.0745,
|
||||
longitude: 119.2965,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Nanchang',
|
||||
latitude: 28.6820,
|
||||
longitude: 115.8579,
|
||||
country: china,
|
||||
timezone: 'Asia/Shanghai',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
egypt = Country.find_by code: 'EG'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Alexandria',
|
||||
latitude: 31.2001,
|
||||
longitude: 29.9187,
|
||||
country: egypt,
|
||||
timezone: 'Africa/Cairo',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
france = Country.find_by code: 'FRA'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Paris',
|
||||
latitude: 48.8566,
|
||||
longitude: 2.3522,
|
||||
country: france,
|
||||
timezone: 'Europe/Paris',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
germany = Country.find_by code: 'DE'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Frankfurt',
|
||||
latitude: 50.1109,
|
||||
longitude: 8.6821,
|
||||
country: germany,
|
||||
timezone: 'Europe/Berlin',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Berlin',
|
||||
latitude: 52.5200,
|
||||
longitude: 13.4050,
|
||||
country: germany,
|
||||
timezone: 'Europe/Berlin',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
india = Country.find_by code: 'IN'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Mumbai',
|
||||
latitude: 19.0760,
|
||||
longitude: 72.8777,
|
||||
country: india,
|
||||
timezone: 'Asia/Kolkata',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Bengaluru',
|
||||
latitude: 12.9716,
|
||||
longitude: 77.5946,
|
||||
country: india,
|
||||
timezone: 'Asia/Kolkata',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
japan = Country.find_by code: 'JP'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Tokyo',
|
||||
latitude: 35.6762,
|
||||
longitude: 139.6503,
|
||||
country: japan,
|
||||
timezone: 'Asia/Tokyo',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Yokohama',
|
||||
latitude: 35.4437,
|
||||
longitude: 139.6380,
|
||||
country: japan,
|
||||
timezone: 'Asia/Tokyo',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
mexico = Country.find_by code: 'MX'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Mexico City',
|
||||
latitude: 19.4326,
|
||||
longitude: -99.1332,
|
||||
country: mexico,
|
||||
timezone: 'America/Mexico_City',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
nigeria = Country.find_by code: 'NG'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Lagos',
|
||||
latitude: 6.5244,
|
||||
longitude: 3.3792,
|
||||
country: nigeria,
|
||||
timezone: 'Africa/Lagos',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
pakistan = Country.find_by code: 'PK'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Lahore',
|
||||
latitude: 31.5204,
|
||||
longitude: 74.3587,
|
||||
country: pakistan,
|
||||
timezone: 'Asia/Karachi',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
russia = Country.find_by code: 'RU'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Moscow',
|
||||
latitude: 55.7558,
|
||||
longitude: 37.6173,
|
||||
country: russia,
|
||||
timezone: 'Europe/Moscow',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Sankt Petersburg',
|
||||
latitude: 59.9311,
|
||||
longitude: 30.3609,
|
||||
country: russia,
|
||||
timezone: 'Europe/Moscow',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
saudi_arabia = Country.find_by code: 'CA'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Riyadh',
|
||||
latitude: 24.7136,
|
||||
longitude: 46.6753,
|
||||
country: saudi_arabia,
|
||||
timezone: 'Asia/Riyadh',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
singapore = Country.find_by code: 'SG'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Singapore',
|
||||
latitude: 1.3521,
|
||||
longitude: 103.8198,
|
||||
country: singapore,
|
||||
timezone: 'Asia/Singapore',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
south_korea = Country.find_by code: 'KR'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Seoul',
|
||||
latitude: 37.5665,
|
||||
longitude: 126.9780,
|
||||
country: south_korea,
|
||||
timezone: 'Asia/Seoul',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
thailand = Country.find_by code: 'TH'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Bangkok',
|
||||
latitude: 13.7563,
|
||||
longitude: 100.5018,
|
||||
country: thailand,
|
||||
timezone: 'Asia/Bangkok',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
turkey = Country.find_by code: 'TR'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'İstanbul',
|
||||
latitude: 41.0082,
|
||||
longitude: 28.9784,
|
||||
country: turkey,
|
||||
timezone: 'Europe/Istanbul',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Ankara',
|
||||
latitude: 39.9334,
|
||||
longitude: 32.8597,
|
||||
country: turkey,
|
||||
timezone: 'Europe/Istanbul',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,13 +0,0 @@
|
||||
uk = Country.find_by code: 'GB'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'London',
|
||||
latitude: 51.5074,
|
||||
longitude: -0.1278,
|
||||
country: uk,
|
||||
timezone: 'Europe/London',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,40 +0,0 @@
|
||||
usa = Country.find_by code: 'US'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'San Francisco',
|
||||
latitude: 37.7749,
|
||||
longitude: -122.4194,
|
||||
country: usa,
|
||||
timezone: 'America/Los_Angeles',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Chicago',
|
||||
latitude: 41.8781,
|
||||
longitude: -87.6298,
|
||||
country: usa,
|
||||
timezone: 'America/Chicago',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'New York City',
|
||||
latitude: 40.7128,
|
||||
longitude: -74.0060,
|
||||
country: usa,
|
||||
timezone: 'America/New_York',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Los Angeles',
|
||||
latitude: 34.0522,
|
||||
longitude: -118.2437,
|
||||
country: usa,
|
||||
timezone: 'America/Los_Angeles',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -1,22 +0,0 @@
|
||||
vietnam = Country.find_by code: 'VN'
|
||||
|
||||
City.create!([
|
||||
{
|
||||
name: 'Ho Chi Minh City',
|
||||
latitude: 10.8231,
|
||||
longitude: 106.6297,
|
||||
country: vietnam,
|
||||
timezone: 'Asia/Ho_Chi_Minh',
|
||||
active: true,
|
||||
priority: 100
|
||||
},
|
||||
{
|
||||
name: 'Hanoi',
|
||||
latitude: 21.0285,
|
||||
longitude: 105.8542,
|
||||
country: vietnam,
|
||||
timezone: 'Asia/Ho_Chi_Minh',
|
||||
active: true,
|
||||
priority: 100
|
||||
}
|
||||
])
|
@ -32,7 +32,7 @@ namespace :geo do
|
||||
region.update!(
|
||||
name: data["name"],
|
||||
code: data["name"],
|
||||
translations: data["translations"],
|
||||
translations: data["translations"].to_json.to_s,
|
||||
flag: data["flag"] || true,
|
||||
wiki_data_id: data["wikiDataId"]
|
||||
)
|
||||
@ -55,7 +55,7 @@ namespace :geo do
|
||||
count += 1
|
||||
|
||||
subregion.update!(
|
||||
translations: data["translations"],
|
||||
translations: data["translations"].to_json,
|
||||
flag: data["flag"] || true,
|
||||
wiki_data_id: data["wikiDataId"]
|
||||
)
|
||||
@ -106,8 +106,8 @@ namespace :geo do
|
||||
tld: data["tld"],
|
||||
native: data["native"],
|
||||
nationality: data["nationality"],
|
||||
timezones: data["timezones"],
|
||||
translations: data["translations"],
|
||||
timezones: data["timezones"].to_json,
|
||||
translations: data["translations"].to_json,
|
||||
latitude: data["latitude"],
|
||||
longitude: data["longitude"],
|
||||
emoji: data["emoji"],
|
||||
|
7
test/controllers/rss_controller_test.rb
Normal file
7
test/controllers/rss_controller_test.rb
Normal file
@ -0,0 +1,7 @@
|
||||
require "test_helper"
|
||||
|
||||
class RssControllerTest < ActionDispatch::IntegrationTest
|
||||
# test "the truth" do
|
||||
# assert true
|
||||
# end
|
||||
end
|
Loading…
Reference in New Issue
Block a user