Upload
others
View
5
Download
0
Embed Size (px)
Citation preview
Internationalization (I18n)
Ziele
Begriff "Internationalization"
Unterscheidung der anzupassenden Inhalte
Einsatz Ruby on Rails
Programmieraspekte, um Internationalisierung zu ermöglichen
Was muss internationalisiert werden?
Typische Übersetzungen in Webapplikationen
Texte in Templates
Lokalisierte Texte (Zeit, Datum, Währung, Nummernformat)
Fehlermeldungen
Model Klassen Namen und Felder Namen
URLs
Bilder, Logos
CSS
Inhalte von Feldern
Quellen der Übersetzungen
Texte in Templates: Programmierung
Lokalisierte Texte (Zeit, Datum, Währung, Nummernformat): Programmierung
Fehlermeldungen: Programmierung
Model Klassen Namen und Felder Namen: Programmierung
URLs: Programmierung
CSS: Programmierung / Grafiker
Bilder, Logos: Grafiker
Inhalte von Feldern: Datenbank
Übersetzungen und REST
shop.com/product?locale=de - shop.com/product?locale=en
shop.com/de/product - shop.com/en/product
your.shop.ch/product - your.shop.com/product
de.shop.com/product - en.shop.com/product
HTTP Header: Accept-Language: de, en-gb;
Nicht! session[:locale] = :de
Konfigurationsfile in Ruby
Verwendete Lokalisationen und Defaulteinstellung.File muss als UTF-8 gespeichert sein!
Anstelle von UTF-8 kann auch HTMLencoding verwendet werden, aberunübersichtlich:
1. #encoding: utf-82. I18n.default_locale = :en3. 4. LANGUAGES = [5. ["English", 'en'],6. ["Español", 'es'], 7. ["日本語", 'ja']8. ]
1. I18n.default_locale = :en2. 3. LANGUAGES = [4. ["English", 'en'],5. ["Español".html_safe, 'es'], 6. ["日本語".html_safe, 'ja']7. ]
Umsetzung Routing
1. Depot::Application.routes.draw do2. ...3. scope '(:locale)' do resources :orders4. resources :line_items5. resources :carts6. ...7. end8. end
Umsetzung Controller
1. class ApplicationController < ActionController::Base2. before_action :set_i18n_locale_from_params3. 4. # ...5. 6. def set_i18n_locale_from_params7. if params[:locale]8. if I18n.available_locales.map(&:to_s).include?(params[:locale])9. I18n.locale = params[:locale]10. else11. flash.now[:notice] =12. "#{params[:locale]} translation not available"13. logger.error flash.now[:notice]14. end15. end16. end17. 18. end
Übersetzungen im View Layer
1. <%= @page_title || t('.title') %>2. <%= t('.home') %>3. <%= button_to t('.add_html'), line_items_path(product_id: product), ...
Übersetzungen pflegen
/config/locales/en.yml
1. en:2. store:3. index:4. title_html: "Your Catalog"5. add_html: "Add to Cart"6. ...
1. de:2. store:3. index:4. title_html: "Ihr Katalog"5. add_html: "Zum Warenkorb hinzufügen"6. ...
Zahlen, Währungen, Datumsformate etc.
/config/locales/en.yml
1. date:2. formats:3. short_datetime: "%B %d, %Y"4. normal_datetime: "%m/%d/%Y"5. 6. number:7. currency:8. format:9. unit: "$"10. precision: 211. separator: "."12. delimiter: ","13. format: "%u%n"
1. <%= l Date.today , :format => :short_datetime %>
Häufig gebrauchte Übersetzungen und Formatierungen
https://github.com/svenfuchs/rails-i18n/tree/master/rails/locale
de-CH: date: abbr_day_names: - So - Mo ... abbr_month_names: - - Jan - Feb - Mär day_names: - Sonntag - Montag - Dienstag ... formats: default: ! '%d.%m.%Y' long: ! '%e. %B %Y' short: ! '%e. %b' month_names: - - Januar - Februar - März - April ... distance_in_words: about_x_hours: one: etwa eine Stunde other: etwa %{count} Stunden about_x_months: one: etwa ein Monat other: etwa %{count} Monate about_x_years: one: etwa ein Jahr other: etwa %{count} Jahre ...
Keine algorithmische Stringkonstruktionen!
Definition der Texte als ganze, parametrisierte Texte:
Verschiedene Textbausteine, um Plural abzufangen
1. #Richtig2. message: "You have ordered %{count} on %{orderDate}"3. ...4. <%= t('.message', count: myCount, orderDate: myDate) %>5. 6. #Falsch7. part1: "You have ordered"8. part2: "items on "9. ...10. <%= t('.part1') + myCount + t('.part2') + myDate %>
Fehlermeldungen
/config/locales/de.yml
1. activerecord:2. errors:3. messages:4. inclusion: "ist nicht in der Liste vorhanden"5. blank: "ist leer"6. errors:7. template:8. body: "Die Einträge in folgenden Feldern sind fehlerhaft:"9. header:10. one: "Aufgrund eines Fehlers kann %{model} nicht gespeichert werden"11. other: "Aufgrund von %{count} Fehlern kann %{model} nicht gespeichert
werden"12.
Locale-Switcher
1. <%= form_tag store_path, class: 'locale' do %>2. <%= select_tag 'set_locale', 3. options_for_select(LANGUAGES, I18n.locale.to_s),4. onchange: 'this.form.submit()' %>5. <%= submit_tag 'submit' %>6. <%= javascript_tag "$('.locale input').hide()" %>7. <% end %> 8.
1. def index2. if params[:set_locale]3. redirect_to store_url(locale: params[:set_locale])4. else5. @products = Product.order(:title)6. end7. end
Übersetzungen von Inhalten
Inhalte gespeichert in Datenbank
Erst zur Laufzeit bekannt
Spezielle Datenbank Designs, z.B Übersetzungstabellen1. class Post < ActiveRecord::Base2. translates :title, :text3. end
1. class CreatePosts < ActiveRecord::Migration2. def up3. create_table :posts do |t|4. t.timestamps5. end6. Post.create_translation_table! :title => :string, :text => :text7. ...
Konzepte der I18n in Java
Internationalisierungs-APIs funktionieren oft ähnlich
1. Locale deCh = new Locale("de", "CH")
1. # This is the LabelsBundle_de.properties file2. s1 = Computer3. s2 = Platte4. s3 = Monitor5. s4 = Tastatur
1. ResourceBundle labels = ResourceBundle.getBundle("LabelsBundle", currentLocale);2. String value = labels.getString(key);
Ein Beispiel aus der Praxis (JavaScript)
Default Fallbacks falls Übersetzungstext nicht verfügbar:
1. Defaultsprache, z.B. Englisch
2. Technischer Name
1. qx.convertToLocale = function (txtid, lang, args) {2. 3. var englishTexts = qx.localizedStrings['en'];4. var localizedTexts = qx.localizedStrings[lang];5. 6. if (localizedTexts === undefined) {7. localizedTexts = englishTexts;8. if (localizedTexts === undefined) { return msgid; }9. 10. var localizedText = localizedTexts[txtid];11. if (localizedText === undefined ) {12. localizedText = englishTexts[txtid];13. if (localizedText === undefined) {14. localizedText = txtid;15. }16. }17. 18. if (arguments.length > 2) {19. var fmt = localizedText;20. var fmtarg = Array.prototype.splice.call(arguments, 2);21. localizedText = fmt.format(fmtarg);22. }23. 24. return localizedText;25. 26. };
Sprachabhängige Sortierung
Alphabetische Sortierung ist nicht gleich ASCII/UTF-Sortierung!
Beispiel: Sortierung von schwedischen Ortsnamen:
Auf Deutsch: Auf Schwedisch:
1. Åkersberga
2. Alingsås
3. Borås
4. Göteborg
5. Örebro
6. Stockholm
1. Alingsås
2. Borås
3. Göteborg
4. Stockholm
5. Åkersberga
6. Örebro
Collator-Klasse in Java, localeCompare in JavaScript ...
Noch extremer in fernöstlichen Sprachen wie Japanisch
Aufgepasst bei dynamisch erzeugten Katalogen
Ein schlechtes Beispiel, gesehen bei einem grossen internationalen Softwarehersteller...
Zusammenfassung
I18N bedeutet:
Übersetzen aller Texte
Anpassen von Formaten für Zahlen, Währungen, Datum etc.
Allenfalls auch CSS, Grafiken
Alle lokalisierungsspezifischen Angaben in einer Datei pro Locale
Einige Punkte sind bei der Programmierung zu beachten
Encoding / Multi-Byte-Fähigkeit
Stringmanipulation
Sprachspezifisches String-Handling