WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin

WordPress Plugins und Themes übersetzbar machen - WP Camp 2012 Berlin

WordPress Plugins und Themes übersetzbar machen - die Grundprinzipien, Grundfunktionen, hilfreiche Tipps, Tricks, Erfahrungen, häufige Fehler und Best Practices

28d02f8d09fc32fccc0282efdc23a4e5?s=128

David Decker

October 13, 2012
Tweet

Transcript

  1. David Decker · deckerweb.de · WP Camp 2012 WordPress Plugins

    und Themes übersetzbar machen Session: define( 'WPLANG', 'de_DE' ); $wp_local_package = 'de_DE';
  2. David Decker · deckerweb.de · WP Camp 2012 Themes &

    Plugins nicht übersetzbar... nur halbgar übersetzbar... Ursachen: Fehlendes Wissen Keine Lust, beratungsresistent... Nur Fokus auf USA... Keine Tests durchgeführt Eigene Implementationen jenseits der Standards
  3. David Decker · deckerweb.de · WP Camp 2012 Selbst Hand

    anlegen WordPress bringt alles mit! via PHP Gettext Gettext Funktionen Textdomain laden: allgemein Plugins Themes Child Themes
  4. David Decker · deckerweb.de · WP Camp 2012 Einpflegen? Nützlich

    bei allen öffentlichen Repo-Projekten GitHub.com - simpel & elegant! WordPress.org: Entwickler kontaktieren Ziel: Nutzen für alle!
  5. David Decker · deckerweb.de · WP Camp 2012 Implementieren Textdomain

    laden: load_textdomain() load_plugin_textdomain() load_theme_textdomain() load_child_theme_textdomain() Für Text-Strings: Regulär: __() _e() _x() _ex() _n() Spezial: _n_noop() translate_nooped_plural() _nx_noop() number_format_i18n() date_i18n() Sicherheit: esc_html__() esc_html_e() esc_html_x() esc_attr__() esc_attr_e() esc_attr_x()
  6. David Decker · deckerweb.de · WP Camp 2012 Plugins: dein-plugin.php

    Kopfbereich, Metadaten: /** * Text Domain: dein-plugin-name-slug * Domain Path: rel-sprachdatei-pfad */ add_action( 'init', 'ddw_wpcamp_plugin' ); function ddw_wpcamp_plugin() { load_plugin_textdomain( 'deine-textdomain', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } Hook „init“ am besten (WMPL!), „plugins_loaded“ ginge wohl auch evtl. Priorität ändern! (experimentieren!) Zusatz: dirname( plugin_basename( __FILE__ ) ) . '/languages/' könnte gefiltert werden (bei Plugins relative Pfade beachten!)
  7. David Decker · deckerweb.de · WP Camp 2012 Themes: style.css

    Kopfbereich, Metadaten: /* Text Domain: dein-theme-name-slug Domain Path: rel-sprachdatei-pfad */ add_action( 'init', 'ddw_wpcamp_theme' ); function ddw_wpcamp_theme() { load_theme_textdomain( 'deine-textdomain', get_template_directory() . '/languages/' ); } Hook „init“ am besten (WMPL!), „after_setup_theme“ evtl. auch evtl. Priorität ändern! (experimentieren!) Zusatz: get_template_directory() . '/languages/' sollte gefiltert werden
  8. David Decker · deckerweb.de · WP Camp 2012 Child Themes:

    style.css Kopfbereich, Metadaten: /* Text Domain: dein-child-theme-slug Domain Path: rel-sprachdatei-pfad */ add_action( 'init', 'ddw_wpcamp_child_theme' ); function ddw_wpcamp_child_theme() { load_child_theme_textdomain( 'deine-child_textdomain', get_stylesheet_directory() . '/languages/' ); } Hook „init“ am besten (WMPL!), „after_setup_theme“ evtl. auch evtl. Priorität ändern! (experimentieren!) Zusatz: get_stylesheet_directory() . '/languages/' könnte gefiltert werden
  9. David Decker · deckerweb.de · WP Camp 2012 Themes: Sprachdatei-Ordner

    filtern /** Set filter for parent themes' languages directory */ $parent_theme_lang_dir = get_template_directory() . '/languages/'; $parent_theme_lang_dir = apply_filters( 'parent_theme_lang_dir', $parent_theme_lang_dir ); add_action( 'init', 'ddw_wpcamp_theme' ); function ddw_wpcamp_theme() { load_theme_textdomain( 'deine-textdomain', $parent_theme_lang_dir ); }
  10. David Decker · deckerweb.de · WP Camp 2012 Plugins vs.

    Themes: Dateinamen der Sprachdateien Themes: de_DE.mo /.po nl_NL.mo /.po fi.mo /.po Plugins: deine-textdomain-de_DE.mo /.po deine-textdomain-nl_NL.mo /.po deine-textdomain-fi.mo /.po Lokale ermitteln: schau bei WPLANG in der wp-config.php! Oder hier recherchieren: http://codex.wordpress.org/WordPress_in_Your_Language
  11. David Decker · deckerweb.de · WP Camp 2012 Themes vs.

    Child Themes get_template_directory() vs. get_stylesheet_directory() load_textdomain() vs. load_child_theme_textdomain() (Child) Themes funktionieren aber auch mit load_textdomain() Streitfrage: Eigene Textdomains für Child Themes JA oder NEIN? DECKERWEB: JA, bitte eigene Domain für Child Themes! = klare Trennung = klarere Organisation = einfachere Pflege (Kundenprojekte...!) plus bessere Performance
  12. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele I

    Korrekt: Templates: <?php _e( 'Germany consists of 16 federal states', 'textdomain' ); ?> In Funktionen: echo __( 'Germany consists of 16 federal states', 'textdomain' ); $string = __( 'Germany consists of 16 federal states', 'textdomain' );
  13. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele II

    Falsch: $string = __( $string, 'textdomain' ); $string = __( "Germany consists of $number federal states", 'textdomain' ); $string = __( 'Germany consists of 16 federal states', $text_domain ); $string = __( 'Germany consists of 16 federal states', PLUGIN_DOMAIN ); $string = __( 'Germany consists of ', 'textdomain' ) . $number . __( ' federal states', 'textdomain' ); Immer: Single Quotes! EINE (1) Textdomain: String in Single Quotes
  14. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele III

    Erweitert: $string = sprintf( __( 'Germany consists of %d federal states', 'textdomain' ), $number ); $string = sprintf( _n( 'Germany consists of %d federal state', 'Germany consists of %d federal states', $number, 'textdomain' ), $number ); $string = sprintf( __( 'I have %d bikes and %d cars', 'textdomain' ), $bike_count, $car_count ); $string = sprintf( __( 'I have %1$d bikes and %2$d cars', 'textdomain' ), $bike_count, $car_count ); Hinweis: "%1$s" macht Probleme (PHP: $s !!!), daher Single Quotes
  15. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele IV

    Kontext: $string = _x( 'Frankfurt', 'German city at the river Main', 'textdomain' ); $string = _x( 'Frankfurt', 'German city at the river Oder', 'textdomain' ); $string = _x( 'Frankfurt', 'an asteroid', 'textdomain' );
  16. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele V

    Formatierungen: $string = sprintf( __( '<h1>I want %d Hefeweizen</h1>', 'textdomain' ), $number ); $string = '<h1>' . sprintf( __( 'I want %d Hefeweizen', 'textdomain' ), $number ) . '</h1>'; $string = sprintf( __( 'I want %s Hefeweizen', 'textdomain' ), '<strong>' . $number . '</strong>' ); Grundregel: KEINE oder so WENIG HTML-Formatierungen wie irgend möglich in den Übersetzungs-Strings!
  17. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele VI

    Sicherheit: Benutzereingaben: esc_html__() esc_html_e() esc_html_x() Ausgaben von Text in HTML-Attributen: esc_attr__() esc_attr_e() esc_attr_x()
  18. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele -

    Spezial I Numerical No-op: $string = sprintf( _n( 'I have %d bike.', 'You have %d bikes.', $number, 'textdomain' ), $number ); $bikes_plural = _n_noop( 'I have %d bike.', 'You have %d bikes.', 'textdomain' ); $string = sprintf( translate_nooped_plural( $bikes_plural, $number ) , $number );
  19. David Decker · deckerweb.de · WP Camp 2012 Syntaxbeispiele -

    Spezial II Zahlen & Daten: number_format_i18n() date_i18n()
  20. David Decker · deckerweb.de · WP Camp 2012 Häufige Fehler:

    Gar keine Übersetzbarkeit Übersetzbarkeit JA, aber kein „load_textdomain“ Mischen von Single & Double Quotes HTML in den Übersetzungs-Strings Falscher Einsatz von Platzhaltern/ Variablen Zu spätes Laden/ Einhängen der Sprachdatei, bzw. vergessen bei Fehlermeldungen/ Aktivierungs-Hooks etc. Eigene „Erfindungen“ fürs Laden der Sprachdateien Keine Verwendung von Kontext, Datum, Plural etc.
  21. David Decker · deckerweb.de · WP Camp 2012 Best Practices

    I ALLES Übersetzbar machen! Laden der Sprachdateien via Hook! Textdomain als String in Single Quotes setzen Generell nur Single Quotes HTML-Formatierungen raus aus den Strings!!! Beliebige Anordnung der Platzhalter ermöglichen via %1$d, %2$d etc. Sicherheit: ESCAPEN bei Benutzereingaben und bei Ausgaben in Attributen!
  22. David Decker · deckerweb.de · WP Camp 2012 Best Practices

    II Pfadangaben checken! load_textdomain() fordert absoluten Pfad load_plugin/theme/child_theme_textdomain() fordern relativen Pfad BONUS 1: Sprachdatei-Ordner filterbar machen bzw. Zusätzlichen Ort für Update-sichere Sprachdateien bereitstellen BONUS 2: Ein GlotPress aufsetzen, um der Community das Übersetzen zu erleichtern... ;-)
  23. David Decker · deckerweb.de · WP Camp 2012 Werkzeuge: define(

    'WP_DEBUG', true ); (wp-config.php) define( 'WPLANG', 'de_DE' ); (wp-config.php) Plugin: „Codestyling Localization“ (zum eigentlichen Übersetzen) Software/ Installation: GlotPress (übersetzen, Export/Import .mo/.po, Verwalten) Lokale Software: PoEdit Editor (übersetzen, validieren -- gut für Platzhalter-Tests!) Testen! Testen! Testen!
  24. David Decker · deckerweb.de · WP Camp 2012 Codestyling Localization

  25. David Decker · deckerweb.de · WP Camp 2012 Codestyling Localization

  26. David Decker · deckerweb.de · WP Camp 2012 GlotPress Installation

  27. David Decker · deckerweb.de · WP Camp 2012 GlotPress Installation

  28. David Decker · deckerweb.de · WP Camp 2012 GlotPress Installation

  29. David Decker · deckerweb.de · WP Camp 2012 PoEdit Editor

    (poedit.net)
  30. David Decker · deckerweb.de · WP Camp 2012 Verwendete Quellen:

    http://ottopress.com/2012/internationalization-youre-probably-doing-it- wrong/ http://ottopress.com/2012/more-internationalization-fun/ http://genesisthemes.de/en/2011-12/seven-cardinal-sins-localizing- wordpress-plugins-themes/ http://codex.wordpress.org/I18n_for_WordPress_Developers http://pippinsplugins.com/localizing-and-translating-wordpress-plugins/ http://remkusdevries.com/how-to-use-glotpress-for-your-translations/
  31. David Decker · deckerweb.de · WP Camp 2012 David Decker

    @deckerweb +David Decker deckerweb.de deckerweb.de/sprachdateien translate.wpautobahn.com Danke! Fragen jetzt! Folien unter: deckerweb.de/wpcamp2012 plus: slideshare.net/deckerweb
  32. David Decker · deckerweb.de · WP Camp 2012 /** Call

    for break and add next session */ add_action( 'wpcamp_berlin_2012', 'wpc_next_session_planning' ) function wpc_next_session_planning() { if ( is_break( array( 10min, coffee, wc ) ) ) { wpcamp_do_next_session(); echo __( 'Enjoy the break', 'wpcamp' ); } else { wpcamp_do_celebrate_community(); echo __( 'Enjoy the conversation', 'wpcamp' ); } }