Nie jest to najlepszy sposób bo nie powinno się tak robić ale :
W application.rb naleÂży przeciżyć dwie metody np w taki sposób
class ApplicationController < ActionController::Base
…
class ActionView::Base
def error_messages_for(object_name, options = {})
options = options.symbolize_keys
object = instance_variable_get("@#{object_name}")
unless object.errors.empty?
content_tag(“div”,
content_tag(
options[:header_tag] || “h2”,
“Wystąpiła następująca ilość błędów związanych z obiektem '#{object_name.to_s.gsub(”_", " “)}’: #{object.errors.count}”
) +
content_tag(“p”, “Wystąpił problem z następującymi polami”) +
content_tag(“ul”, object.errors.full_messages.collect { |msg| content_tag(“li”, msg) }),
“id” => options[:id] || “errorExplanation”, “class” => options[:class] || “errorExplanation”
)
end
end
end
class ActiveRecord::Errors
def full_messages
full_messages = []
@errors.each_key do |attr|
@errors[attr].each do |msg|
next if msg.nil?
if attr == "base"
full_messages << msg
else
full_messages << msg
end
end
end
return full_messages
end
end
…
end
Pierwsza definiuje message o błędach, druga pozwala na uniknięcie nazw zmiennych podczas wyświetlania błędów.
Może ktoś zna lepszy sposób, właśnie wrociłem do pisania stronki po jakichś 2 miesiącach przerwy. Coś sie ruszyło z internacjonalizacją, szczegłlnie na polu zakodowanych na sztywno messegów ?
Pozdrawiam, Jacek Balcerski
przystepujemy do prawdziwej zmiany - w app/exts tworzymy folder active_record, a w nim plik validations.rb - w ten sposob utrzymujemy konwencje z railsow; zawartosc app/exts/validations.rb:
[code=“ruby”]module ActiveRecord
class Errors
begin
# tlumaczenia ofcoz trzeba dokonac samodzielnie…
@@default_error_messages.update( {
:inclusion => “is not included in the list”,
:exclusion => “is reserved”,
:invalid => “is invalid”,
:confirmation => “doesn’t match confirmation”,
:accepted => “must be accepted”,
:empty => “can’t be empty”,
:blank => “can’t be blank”,
:too_long => “is too long (max is %d characters)”,
:too_short => “is too short (min is %d characters)”,
:wrong_length => “is the wrong length (should be %d characters)”,
:taken => “has already been taken”,
:not_a_number => “is not a number”
})
end
alias :old_on_blank :add_on_blank
# a to jest moja wersja metody ktora nie robi nic sensownego ale pokazuje
# jakby co - to mozna ;)
def add_on_blank(attributes, msg = @@default_error_messages[:empty])
old_on_blank(attributes, msg)
end
end
end[/code]
4. dodajemy obsluge naszych swiezych zmian do aplikacji - w pliku app/config/environment.rb na koncu dodajemy linijke wlaczajaca nasze zmiany:
require "#{RAILS_ROOT}/app/exts/all"
Taki sposob podejscia pozwala utrzymac w jednym miejscu wszystkie modyfikacje orginalnego zachowania railsow. Tworzy sie plik i umieszcza w stosownym katalogu pod app/exts i voila - wlaczone i zaaplikowane…
oops to moj pierwszy post - wiec witam wszystkich bardzo serdecznie !!
Witam rubberów!
czy wie ktoś może jak przetłumaczyć nazwy kolumn i tabel, tak aby w walidacji nie pojawiało mi się password a hasło, chociaż w bazie mam nazwę password. Doinstalowałem plugin Globalize i chcę mieć wszystko w 2 językach.
Dzięki!
Poważnie? Ja nie zauważyłem jakiejś słabej wydajności. Zwykle pobierane są krótkie teksty, są poindeksowane. Relacyjna baza danych jest bardzo szybka, bo wykorzystuje własny cache do takich niedużych operacji.
To, że używana jest baza danych to tylko zaleta. Np. proces tłumaczenia nie wymaga co chwilę restartowania Mongrela aby zmiany były widoczne w serwisie. Gettext nadaje się tylko do tłumaczenia interfejsu. Globalize pozwala zaś też tworzyć wiele wersji językowych dla tekstów trzymanych w bazie mi ładnie te wersje się przełączają.
No ja sie zgadzam ze gettextu nie nalezy uzywac do tworzenia roznych dokumentow juz bezposrednio na strone, natomiast przeciez jest to standardowy system lokalizawania walsnie interfejsu, ale sa gusta i gusciki Ja sie zrazilem do globalize
[quote=balcer]Nie jest to najlepszy sposób bo nie powinno się tak robić ale :
W application.rb naleÂży przeciżyć dwie metody np w taki sposób
class ApplicationController < ActionController::Base
…
class ActionView::Base
def error_messages_for(object_name, options = {})
(…)
class ActiveRecord::Errors
(…)
end
Pierwsza definiuje message o błędach, druga pozwala na uniknięcie nazw zmiennych podczas wyświetlania błędów.
Może ktoś zna lepszy sposób, właśnie wrociłem do pisania stronki po jakichś 2 miesiącach przerwy. Coś sie ruszyło z internacjonalizacją, szczegłlnie na polu zakodowanych na sztywno messegów ?
Pozdrawiam, Jacek Balcerski[/quote]
Siedziałem nad tym ładnych parę godzin. I już praktycznie doszedłem do tego samego, ale ten post pozwolił mi to skończyć trochę wcześniej, niż jakbym robił to sam
Według mnie trochę to bez sensu, że nie można ustawić np. error_messages_for i parametru :base (żeby nie pokazywał nazw kolumn), no ale cóż…
Aha, jako że to mój pierwszy post, to witam wszystkich. Pewnie zacznę częściej tu się pojawiać.
aby zmienić nazwy pól wyświetlanych w błędach można spróbować takiego rozwiązania
jesli mamy model user
w pliku user.rb
class User < ActiveRecord::Base
…
validates_presence_of :login, :message => “nie powinno byc puste”
validates_presence_of :email, :message => “nie powinno byc puste”
validates_presence_of :password, :if =>
…
end
class << self
HUMANIZED_ATTRIBUTE_KEY_NAMES = {
“password” => “Pole hasła” ,
“email” => “Pole adresu email” ,
“password_confirmation” => “Pole potwierdzenia hasła”
}
def human_attribute_name(attribute_key_name)
HUMANIZED_ATTRIBUTE_KEY_NAMES[attribute_key_name] || super
end
end
validates_presence_of :something, :message => "^Coś nie powinno być puste"
Daszek ^ chyba sprawi, że w message nie pojawi się nazwa zmiennej?[/quote]
AFAIR do tego chyba trzeba cos spatchowac / wrzucic plugin, bo natywnie tego nie ma.
[code]module ActiveRecord
class Errors
def full_messages_with_custom
full_messages = []
@errors.each_key do |attr|
@errors[attr].each do |msg|
next if msg.nil?
if attr == "base"
full_messages << msg
elsif msg =~ /^\^/ # TUTAJ
full_messages << msg[1..-1]
else
full_messages << @base.class.human_attribute_name(attr) + " " + msg
end
end
end
return full_messages
end
alias_method_chain :full_messages, :custom
end
end[/code]
… ale jak ktos dodatkowo uzywa gettexta, to:
[code]require ‘gettext/active_record’
module ActiveRecord
class Errors
include GetText
def localize_error_message(attr, msg, append_field) # :nodoc:
custom_msg = nil
#Ugly but... :-<
@@default_error_messages_d.dup.merge(@base.custom_error_messages_d).each do |key, regexp|
if regexp =~ msg
custom_msg = @base.gettext(key)
custom_msg = _(msg) if custom_msg == msg
custom_msg = _(custom_msg) % $1.to_i
break
end
end
unless custom_msg
custom_msg = @base.gettext(msg)
custom_msg = _(msg) if custom_msg == msg
end
if attr == "base"
full_message = custom_msg
elsif /^\^/ =~ custom_msg
full_message = custom_msg[1..-1]
elsif /%\{fn\}/ =~ custom_msg
full_message = custom_msg % {:fn => @base.class.human_attribute_name(attr)}
elsif append_field
full_message = @base.class.human_attribute_name(attr) + " " + custom_msg
else
full_message = custom_msg
end
full_message
end
Polecam nam naszego plugina do zamiany komunikatów ActiveRecord na dowolny język:
(wymagane jest zainstalowanie tego pluginu w pierwszej kolejnosci)
Jeśli używacie Gibberisha plugin ten będzie dla was idealny!
Przetłumaczy dla was automatycznie komunikaty w stylu (ponizsze stringi zamiencie na polski):
…
error_blank: “nie może być puste”
error_too_long: “jest zbyt długie (maksimum to %d znaków)”
error_taken: “jest już zajęte”
…
Co wiecej przetłumaczy wam automatycznie labele do formularzy
Zakladajac, ze macie 2 modele User, i Product, gdzie obydwa maja pole: body
Dodajcie do pliku z tlumaczeniem: “attr_#{table_name.singularize}_#{attribute_key_name}”. Np:
attr_user_name: Imię i Nazwisko
attr_product_name: Nazwa produktu
inne pluginy tego typu, które pozwalaja na podobne rzeczy (np. globalite) obydwa pola przetłumaczylyby wam jako: Nazwa …
Jak dla mnie najmniej inwazyjnym sposobem jest przeciążenie ActionView::Base i ActiveRecord::Errors, gdzie w ‘Errors’ pomija się nazwy zmiennych (przeważnie angielskie, bo tak konstruuję swoją bazę).
Wtedy w bardzo prosty sposób przy każdym validates_* dodaję :message, gdzie zawieram nazwę zmiennej, np.: validates_presence_of_password, :message => “Hasło nie może być puste”.
Proste, nieinwazyjne i nie trzeba w kilku miejscach tłumaczyć nazw zmiennych i pamiętać o spójności.
Pytanie tylko czy to w końcu zostało ujęte w jakimś prostym pluginie czy ciągle trzeba to wrzucać do environment.rb (tudzież app/exts).
PS. Ktokolwiek jest odpowiedzialny za ustawienia forum, powinien poprawić godzinę na serwerze. Jest 2 godz. do tyłu.
module ClassMethods
def humanize(attributes)
attributes.stringify_keys!
if read_inheritable_attribute(:human_attribute_names).nil?
class_inheritable_reader(:human_attribute_names)
write_inheritable_attribute(:human_attribute_names, attributes)
self.class_eval do
def self.human_attribute_name(attr)
self.human_attribute_names[attr] || super(attr)
end
end
else
write_inheritable_attribute(:human_attribute_names, read_inheritable_attribute(:human_attribute_names).merge(attributes))
end
end
end
end
end
ActiveRecord::Base.send(:include, ServiceDesk::Humanizer)[/code]
w praktyce wyglada to tak:
[code]class Ticket < ActiveRecord::Base
humanize({
:location_name => “Location”
})
end
class Ticket2 < Ticket
humanize({
:requestor_name => “Requestor”
})
end[/code]
[quote=drogus]Na dzień dzisiejszy to chyba lekko zbędny kod
Railsy korzystają z tłumaczeń i18n domyślnie i korzystając z nich można bez problemu przetłumaczyć nazwy pól.[/quote]
Nie korzystam z i18n, kiepsko sie skaluje na plikach tekstowych, majac 6000 string’ów w aplikacji było by mi bardzo trudno tym zarządzać. Gettext w tym przypadku jest znacznie lepszy. IMHO i18n w rails to niewypał.
Szukałem na necie rozwiązania dla małych aplikacji i nie doszukałem się niczego prostego co bym mógł zakumać.
Zrobiłem to po swojemu (popatrzyłem w źródła validation.rb).
Piszę tutaj, bo może akurat ktoś będzie miał podobny problem.
Ogólnie chodziło o to, że to co jest w standardowym pl.yml to nie za bardzo pasuje nawet do standardowego restfull authentication.
“{attribute} {message}” = “Email nie może być puste”, itp.
Może da się to inaczej zrobić, ale dla mnie jest idealne rozwiązanie, gdyż pasuje do kazdej opcji. Nie muszę się trzymać schematu “{attribute} {message}”. Dodatkowo {message} w tym standardowym pl.yml musi być taki aby pasował do wszystkich {attribute} (jeżeli dobrze rozumiem), co w języku polskim jest niewygodne (“Email jest pustY”, “Hasło jest pustY”, muszą być inne {message}).