Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
fd5c8064d0
chore(deps): bump aws-sdk-core from 3.211.0 to 3.219.0
Bumps [aws-sdk-core](https://github.com/aws/aws-sdk-ruby) from 3.211.0 to 3.219.0.
- [Release notes](https://github.com/aws/aws-sdk-ruby/releases)
- [Changelog](https://github.com/aws/aws-sdk-ruby/blob/version-3/gems/aws-sdk-core/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-ruby/commits)

---
updated-dependencies:
- dependency-name: aws-sdk-core
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-20 06:49:17 +00:00
87 changed files with 1096 additions and 1971 deletions

View File

@ -1,4 +1,4 @@
name: Docker Dev
name: Docker
on:
push:
@ -45,4 +45,4 @@ jobs:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: |
${{ env.REGISTRY }}/${{github.actor}}/${{ github.event.repository.name }}_dev:dev
${{ env.REGISTRY }}/${{github.actor}}/${{ github.event.repository.name }}:dev

View File

@ -1,4 +1,4 @@
name: Docker Main
name: Docker
on:
push:

View File

@ -1 +1 @@
3.3.5
ruby-3.3.5

View File

@ -57,7 +57,7 @@ gem "ruby-openai", "~> 7.3"
gem "httparty", "~> 0.22.0"
gem "down", "~> 5.4"
gem "aws-sdk-s3", "~> 1.170"
gem "aws-sdk-core", "3.211"
gem "aws-sdk-core", "3.219.0"
gem "sidekiq", "~> 7.3"
gem "sidekiq-scheduler", "~> 5.0"
@ -67,8 +67,6 @@ 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"

View File

@ -92,12 +92,13 @@ GEM
activesupport (>= 3.0.0)
ruby2_keywords (>= 0.0.2)
ast (2.4.2)
aws-eventstream (1.3.0)
aws-partitions (1.1044.0)
aws-sdk-core (3.211.0)
aws-eventstream (1.3.1)
aws-partitions (1.1052.0)
aws-sdk-core (3.219.0)
aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9)
base64
jmespath (~> 1, >= 1.6.1)
aws-sdk-kms (1.96.0)
aws-sdk-core (~> 3, >= 3.210.0)
@ -519,11 +520,10 @@ PLATFORMS
DEPENDENCIES
activeadmin (~> 3.2)
ahoy_matey (~> 5.2)
aws-sdk-core (= 3.211)
aws-sdk-core (= 3.219.0)
aws-sdk-s3 (~> 1.170)
bootsnap
brakeman
builder (~> 3.3)
bullet (~> 8.0)
capybara
cssbundling-rails

View File

@ -2,7 +2,6 @@ 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: [
@ -48,7 +47,7 @@ class ApplicationController < ActionController::Base
# Bot: #{browser.bot?}
# BROWSER_INFO
# }
around_action :set_locale
before_action :set_locale
after_action :track_action
def log_browser_info
@ -76,55 +75,7 @@ class ApplicationController < ActionController::Base
private
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"
def set_locale
I18n.locale = params[:locale] || I18n.default_locale
end
end

View File

@ -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}, ai, ai web, ai art, ai weather, weather art, AI visualization",
keywords: "#{@city.name}, #{@city.country.name}, weather art, AI visualization",
og: {
image: @city.latest_weather_art&.image&.attached? ? url_for(@city.latest_weather_art.image) : nil
}

View File

@ -1,9 +0,0 @@
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

View File

@ -1,126 +1,33 @@
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]
key = "sitemaps/#{path}"
Rails.logger.info "Requesting sitemap: #{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}"
begin
# 检查文件是否存在
s3_client.head_object(
bucket: @bucket_name,
key: key
s3_client = Aws::S3::Client.new
response = s3_client.get_object(
bucket: bucket_name,
key: "sitemaps/#{path}"
)
# 生成预签名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" # 在浏览器中直接显示
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"
)
# 设置缓存头
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}"
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
# 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

View File

@ -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}, #{@city.country.name}, ai, ai web, ai art, ai weather, weather art, AI visualization, #{@weather_art.description}",
keywords: "#{@city.name}, weather art, #{@weather_art.description}, AI visualization",
og: {
image: @weather_art.image.attached? ? url_for(@weather_art.image) : nil
}

View File

@ -1,2 +0,0 @@
module RssHelper
end

View File

@ -1,5 +1,2 @@
module SitemapsHelper
def sitemap_url(filename)
"/sitemaps/#{filename}"
end
end

View File

@ -1,22 +0,0 @@
# 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

View File

@ -1,9 +1,8 @@
class Country < ApplicationRecord
include TranslatableName
extend FriendlyId
friendly_id :name, use: :slugged
# before_save :format_json_attributes, :timezones, :translations
before_save :format_timezones
belongs_to :region, optional: true
belongs_to :subregion, optional: true
@ -14,15 +13,14 @@ 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" ]
@ -34,26 +32,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

View File

@ -1,6 +1,4 @@
class Region < ApplicationRecord
include TranslatableName
extend FriendlyId
friendly_id :name, use: :slugged
@ -11,15 +9,13 @@ 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)

View File

@ -79,23 +79,11 @@ class WeatherArt < ApplicationRecord
ActiveSupport::TimeZone["UTC"]
time = self.updated_at
# 使用 I18n 本地化格式化日期
date_string = I18n.l(self.weather_date, format: :long)
# 格式化时间
time_format = use_local_timezone ? time.in_time_zone(time_zone) : time.utc
date_string = self.weather_date&.strftime("%B %d, %Y")
time_string =
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
use_local_timezone ?
"#{time.in_time_zone(time_zone).strftime('%H:%M')} #{timezone_info['gmtOffsetName']}" :
"#{time.utc.strftime('%H:%M')} UTC"
case type
when :date
@ -103,15 +91,9 @@ class WeatherArt < ApplicationRecord
when :time
time_string
when :all
I18n.t("time.formats.date_and_time",
date: date_string,
time: time_string
)
"#{date_string} #{time_string}"
else
I18n.t("time.formats.date_and_time",
date: date_string,
time: time_string
)
"#{date_string} #{time_string}"
end
end

View File

@ -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">
<%= t("arts.title") %>
Weather Arts Gallery
</h1>
<p class="text-xl text-base-content/70">
<%= t("arts.subtitle") %>
Discover AI-generated weather art from cities around the world
</p>
<!-- 如果有特色图片,显示其信息 -->
<% if featured_art %>
<div class="text-sm text-base-content/60 pt-4">
<%= "#{t("text.latest_from")} #{featured_art.city.full_name}" %>
Latest from <%= featured_art.city.name %>, <%= featured_art.city.country.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' ? t("text.oldest_first") : t("text.newest_first") %>
<%= params[:sort] == 'oldest' ? 'Oldest First' : '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 t("text.newest_first"), arts_path(sort: 'newest', region: params[:region]),
<%= link_to "Newest First", arts_path(sort: 'newest', region: params[:region]),
class: "#{'active' if params[:sort] != 'oldest'}" %>
</li>
<li>
<%= link_to t("text.oldest_first"), arts_path(sort: 'oldest', region: params[:region]),
<%= link_to "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&.localized_name || t("text.all_regions") %>
<%= @current_region&.name || '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 t("text.all_regions"), arts_path(sort: params[:sort]),
<%= link_to "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.localized_name, arts_path(region: region.id, sort: params[:sort]),
<%= link_to region.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">
<%= "#{t("text.showing")} #{@weather_arts.total_count} #{t("text.weather_arts")} " %>
Showing <%= @weather_arts.total_count %> weather arts
<% if @current_region %>
from <%= @current_region.localized_name %>
from <%= @current_region.name %>
<% end %>
</div>
</div>
@ -118,7 +118,7 @@
<%= art.city.name %>
</h3>
<p class="text-sm text-white/80">
<%= "#{art.city&.country&.emoji + " " || ""}#{art.city&.country&.localized_name}" %>
<%= art.city.country.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 %>
<%= t("button.view_detail") %>
View Details
<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>

View File

@ -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 %>
<%= t("button.view_detail") %>
View Details
<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 %>
<%= t("button.view_detail") %>
View Details
<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>

View File

@ -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: t("text.search_cities"),
placeholder: "Search cities...",
autocomplete: "off",
data: {
action: "input->search#submit",

View File

@ -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">
<%= t("cities.title") %>
Explore Cities
</h1>
<p class="text-xl md:text-2xl text-base-content/70 font-light max-w-2xl mx-auto">
<%= t("arts.subtitle") %>
Discover AI-generated weather art from cities around the world
</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">
<%= t("text.latest_from") %>
Latest from
<span class="font-semibold"><%= featured_art.city.name %></span>,
<%= featured_art.city.country.localized_name %>
<%= featured_art.city.country.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&.localized_name || t("text.all_regions") %>
<%= @current_region&.name || '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 %>
<%= t("text.all_regions") %>
All Regions
<% end %>
</li>
<div class="divider my-1"></div>
<% @regions.each do |region| %>
<li>
<%= link_to region.localized_name,
<%= link_to region.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&.localized_name || t("text.all_countries") %>
<%= @current_country&.name || "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 "#{t("text.all_in")} #{@current_region.localized_name}",
<%= link_to "All in #{@current_region.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.localized_name}",
<%= link_to "#{country&.emoji + " " || ""}#{country.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.localized_name %>
in <%= @current_country.name %>
<% elsif @current_region %>
in <%= @current_region.localized_name %>
in <%= @current_region.name %>
<% end %>
</div>
</div>

View File

@ -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>
<%= t("button.back_to_cities") %>
Back to Cities
<% end %>
</div>

View File

@ -20,7 +20,7 @@
</div>
</div>
<div class="card-actions justify-end mt-4">
<%= link_to t("button.view_detail"), city_weather_art_path(art.city, art),
<%= link_to "View Details", city_weather_art_path(art.city, art),
class: "btn btn-primary btn-outline" %>
</div>
</div>

View File

@ -11,12 +11,13 @@
<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">
<%= t("home.headline_html") %>
Where Weather Meets<br>Artificial Intelligence
</h1>
<p class="text-xl text-base-content/70 font-sans">
<%= t("home.subtitle") %>
Experience weather through the lens of AI-generated art,
bringing a new perspective to daily meteorological phenomena.
</p>
<%= link_to t("button.explore_cities"), cities_path,
<%= link_to "Explore Cities", cities_path,
class: "btn btn-primary btn-lg mt-8 font-sans" %>
</div>
</div>
@ -24,9 +25,9 @@
<!-- 最新天气艺术 -->
<section class="container mx-auto px-4 py-16 space-y-12">
<h2 class="text-3xl font-display font-bold text-center"><%= t("title.latest_weather_art") %></h2>
<h2 class="text-3xl font-display font-bold text-center">Latest Weather Art</h2>
<%= render 'home/arts', arts: @latest_arts %>
<h2 class="text-3xl font-display font-bold text-center"><%= t("title.popular_weather_art") %></h2>
<h2 class="text-3xl font-display font-bold text-center">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 %>
@ -34,7 +35,7 @@
</div>
<div class="text-center mt-12 mb-12">
<%= link_to arts_path, class: "btn btn-primary btn-lg gap-2" do %>
<%= t("button.view_all_weather_arts") %>
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>

View File

@ -1,18 +1,6 @@
<!-- 页脚 -->
<footer class="footer footer-center p-8 bg-base-200 text-base-content">
<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 class="container mx-auto flex flex-col gap-2">
<div id="busuanzi_container" class="text-xs opacity-70">
<div class="space-x-2">
<span>Page: </span>
@ -22,14 +10,13 @@
<span>PV <span id="busuanzi_site_pv"></span></span>
<span>UV <span id="busuanzi_site_uv"></span></span>
<span data-controller="page-load-time">
Load Time: <span data-page-load-time-target="timer">x</span> ms
Page Load Time: <span data-page-load-time-target="timer">x</span> ms
</span>
</div>
</div>
<!-- 第三行:版权信息 -->
<p class="font-display opacity-80 text-sm">
Copyright © <%= Time.current.year %> - All rights reserved by AI Weather Art
<p class="font-display opacity-80">
Copyright © 2024 - All rights reserved by AI Weather Art
</p>
</div>
</footer>
</footer>

View File

@ -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 %>
<%= t('brand.name') %>
Today AI Weather
<% end %>
</div>
<!-- Desktop Menu -->
<div class="hidden md:flex flex-none gap-2 items-center">
<%= 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" %>
<%= 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" %>
<% if user_signed_in? %>
<div class="dropdown dropdown-end">
@ -27,14 +27,12 @@
</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><%= t("title.sign_in") %></span>
<span>Sign in</span>
<% end %>
<% end %>
</div>
@ -48,8 +46,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 t("title.cities"), cities_path %></li>
<li><%= link_to t("title.arts"), arts_path %></li>
<li><%= link_to "Cities", cities_path %></li>
<li><%= link_to "Arts", arts_path %></li>
<div class="divider my-1"></div>
<% if user_signed_in? %>
<li>
@ -58,7 +56,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>
<%= t("title.settings") %>
Settings
<% end %>
</li>
<li>
@ -69,7 +67,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><% t("title.sign_out") %></span>
<span>Sign out</span>
</div>
<% end %>
</li>
@ -79,7 +77,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>
<%= t("title.sign_in") %>
Sign in
<% end %>
</li>
<% end %>

View File

@ -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><%= t("title.settings") %></span>
<span>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><%= t("title.admin_dashboard") %></span>
<span>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><%= t("title.sign_out") %></span>
<span>Sign out</span>
<% end %>
</li>
</ul>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html>
<html lang="<%= I18n.locale %>">
<html lang="en">
<head>
<title><%= content_for(:title) || "Today Ai Weather" %></title>
<meta name="viewport" content="width=device-width,initial-scale=1">
@ -11,14 +11,11 @@
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'),
"ja" => url_for(locale: 'ja'),
"ko" => url_for(locale: 'ko')
"en" => url_for(locale: 'en')
}
) %>
<%= csrf_meta_tags %>
@ -36,8 +33,6 @@
<%# 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>

View File

@ -1,24 +0,0 @@
# 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

View File

@ -1,17 +0,0 @@
<%# 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>

View File

@ -78,12 +78,9 @@
<!-- 结果统计 -->
<div class="text-sm text-base-content/60 font-light">
<%= 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'))
) %>
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' %>
</div>
</div>
<% end %>

View File

@ -1,43 +0,0 @@
<%# 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>

View File

@ -35,7 +35,7 @@
<%= link_to city_weather_art_path(weather_art.city, weather_art),
class: "btn btn-primary btn-block" do %>
<%= t("button.view_detail") %>
View Details
<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>

View File

@ -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"><%= t("card.temperature") %></div>
<div class="stat-title font-medium text-base">Temperature</div>
<div class="stat-value text-3xl"><%= weather_art.temperature %>°C</div>
<div class="stat-desc"><%= t("card.feel_like") %> <%= weather_art.feeling_temp %>°C</div>
<div class="stat-desc">Feels 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"><%= t("card.wind") %></div>
<div class="stat-title font-medium text-base">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"><%= t("card.humidity") %></div>
<div class="stat-title font-medium text-base">Humidity</div>
<div class="stat-value text-3xl"><%= weather_art.humidity %>%</div>
<div class="stat-desc"><%= t("card.relative_humidity") %></div>
<div class="stat-desc">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"><%= t("card.visibility") %></div>
<div class="stat-title font-medium text-base">Visibility</div>
<div class="stat-value text-3xl"><%= weather_art.visibility %> km</div>
<div class="stat-desc"><%= t("card.clear_view_distance") %></div>
<div class="stat-desc">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"><%= t("card.pressure") %></div>
<div class="stat-title font-medium text-base">Pressure</div>
<div class="stat-value text-3xl"><%= weather_art.pressure %> hPa</div>
<div class="stat-desc"><%= t("card.atmospheric_pressure") %></div>
<div class="stat-desc">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"><%= t("card.cloud_cover") %></div>
<div class="stat-title font-medium text-base">Cloud Cover</div>
<div class="stat-value text-3xl"><%= weather_art.cloud %>%</div>
<div class="stat-desc"><%= t("card.sky_coverage") %></div>
<div class="stat-desc">Sky coverage</div>
</div>

View File

@ -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>
<%= "#{t("button.back_to")} #{@weather_art.city.name}" %>
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&.localized_name}" %>
<%= "#{@weather_art&.city&.country&.emoji + " " || ""}#{@city&.country&.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"><%= t("title.ai_prompt") %></h3>
<h3 class="font-display font-bold text-lg">AI Prompt</h3>
</div>
<p class="text-base-content/80 leading-relaxed">
<%= @weather_art.prompt %>

View File

@ -8,25 +8,6 @@ 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
@ -57,6 +38,8 @@ class BatchGenerateWeatherArtsWorker
print_summary(processed_cities, skipped_cities)
end
private
def get_recent_cities
cutoff_time = Time.current - GENERATION_INTERVAL
City.joins("LEFT JOIN (

View File

@ -10,14 +10,7 @@ class RefreshSitemapWorker
if redis.set(lock_key, Time.current.to_s, nx: true, ex: lock_ttl)
begin
setup_sitemap_config
# 生成默认的不带语言前缀的 sitemap
generate_sitemap(nil)
# 为每个可用语言生成带前缀的 sitemap
I18n.available_locales.each do |locale|
generate_sitemap(locale)
end
generate_sitemap
ensure
redis.del(lock_key)
end
@ -28,11 +21,10 @@ class RefreshSitemapWorker
private
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)
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)
if Rails.env.production?
SitemapGenerator::Sitemap.adapter = SitemapGenerator::AwsSdkAdapter.new(
ENV.fetch("AWS_BUCKET", Rails.application.credentials.dig(:minio, :bucket)),
@ -53,77 +45,36 @@ class RefreshSitemapWorker
)
end
SitemapGenerator::Sitemap.sitemaps_path = "sitemaps/"
end
def generate_sitemap(locale = nil)
# 设置当前语言环境
I18n.locale = locale || I18n.default_locale
Rails.application.routes.default_url_options[:locale] = locale
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
# 设置 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, locale: locale),
add city_path(city),
changefreq: "daily",
priority: 0.8,
lastmod: city.updated_at,
alternate: available_locales.map { |al|
{ lang: al, href: city_url(city, locale: al) }
}
lastmod: city.updated_at
end
# 天气艺术作品页
WeatherArt.includes(:city).find_each do |art|
if art.image.attached?
add city_weather_art_path(art.city, art, locale: locale),
add city_weather_art_path(art.city, art),
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')}"
} ],
alternate: available_locales.map { |al|
{ lang: al, href: city_weather_art_url(art.city, art, locale: al) }
}
loc: url_for(art.image),
title: "#{art.city.name} Weather Art - #{art.weather_date.strftime('%B %d, %Y')}"
} ]
end
end
end
Rails.logger.info "Generated sitemap for #{locale || 'default'} version"
# SitemapGenerator::Sitemap.ping_search_engines if Rails.env.production?
Rails.logger.info "Sitemap has been generated and uploaded to S3 successfully"
rescue => e
Rails.logger.error "Error generating sitemap for #{locale || 'default'}: #{e.message}"
raise e
Rails.logger.error "Error refreshing sitemap: #{e.message}"
end
end

View File

@ -1,19 +0,0 @@
# 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

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -0,0 +1,55 @@
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'

View File

@ -0,0 +1,55 @@
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: '澳大利亚'

View File

@ -1,67 +0,0 @@
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"

View File

@ -28,90 +28,4 @@
# enabled: "ON"
en:
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"
hello: "Hello world"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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."

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,66 +0,0 @@
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 日"

View File

@ -1,66 +0,0 @@
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 일"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -0,0 +1,15 @@
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'

View File

@ -0,0 +1,15 @@
zh-CN:
regions:
AS: '亚洲'
SA: '南亚'
SEA: '东南亚'
EA: '东亚'
ME: '中东'
AF: '非洲'
NA: '北非'
SSA: '撒哈拉以南非洲'
EU: '欧洲'
NAM: '北美洲'
SAM: '南美洲'
CAM: '中美洲'
OC: '大洋洲'

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,67 +0,0 @@
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"

View File

@ -1,65 +0,0 @@
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 日"

View File

@ -1,53 +1,49 @@
require "sidekiq/web"
Rails.application.routes.draw do
scope "(:locale)", locale: /#{I18n.available_locales.join("|")}/ do
devise_for :users
root "home#index"
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
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"
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/*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

View File

@ -10,6 +10,11 @@
# 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!([
{
@ -17,14 +22,46 @@ 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'
}
@ -96,6 +133,9 @@ 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!([
{

View File

@ -0,0 +1,22 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

13
db/seeds/cities/brazil.rb Normal file
View File

@ -0,0 +1,13 @@
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
}
])

10
db/seeds/cities/canada.rb Normal file
View File

@ -0,0 +1,10 @@
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
)

346
db/seeds/cities/china.rb Normal file
View File

@ -0,0 +1,346 @@
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
}
])

13
db/seeds/cities/egypt.rb Normal file
View File

@ -0,0 +1,13 @@
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
}
])

13
db/seeds/cities/france.rb Normal file
View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,22 @@
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
}
])

22
db/seeds/cities/india.rb Normal file
View File

@ -0,0 +1,22 @@
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
}
])

22
db/seeds/cities/japan.rb Normal file
View File

@ -0,0 +1,22 @@
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
}
])

13
db/seeds/cities/mexico.rb Normal file
View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

22
db/seeds/cities/russia.rb Normal file
View File

@ -0,0 +1,22 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

View File

@ -0,0 +1,13 @@
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
}
])

22
db/seeds/cities/turkey.rb Normal file
View File

@ -0,0 +1,22 @@
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
}
])

13
db/seeds/cities/uk.rb Normal file
View File

@ -0,0 +1,13 @@
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
}
])

40
db/seeds/cities/usa.rb Normal file
View File

@ -0,0 +1,40 @@
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
}
])

View File

@ -0,0 +1,22 @@
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
}
])

View File

@ -32,7 +32,7 @@ namespace :geo do
region.update!(
name: data["name"],
code: data["name"],
translations: data["translations"].to_json.to_s,
translations: data["translations"],
flag: data["flag"] || true,
wiki_data_id: data["wikiDataId"]
)
@ -55,7 +55,7 @@ namespace :geo do
count += 1
subregion.update!(
translations: data["translations"].to_json,
translations: data["translations"],
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"].to_json,
translations: data["translations"].to_json,
timezones: data["timezones"],
translations: data["translations"],
latitude: data["latitude"],
longitude: data["longitude"],
emoji: data["emoji"],

View File

@ -1,7 +0,0 @@
require "test_helper"
class RssControllerTest < ActionDispatch::IntegrationTest
# test "the truth" do
# assert true
# end
end