wordpress plugins und themes übersetzbar machen - wp camp 2012 berlin
DESCRIPTION
WordPress Plugins und Themes übersetzbar machen - die Grundprinzipien, Grundfunktionen, hilfreiche Tipps, Tricks, Erfahrungen, häufige Fehler und Best PracticesTRANSCRIPT
David Decker · deckerweb.de · WP Camp 2012
WordPress Pluginsund Themesübersetzbar machen
Session:
define( 'WPLANG', 'de_DE' );$wp_local_package = 'de_DE';
David Decker · deckerweb.de · WP Camp 2012
Themes & Pluginsnicht übersetzbar...nur halbgar übersetzbar...
Ursachen: Fehlendes Wissen
Keine Lust, beratungsresistent...
Nur Fokus auf USA...
Keine Tests durchgeführt
Eigene Implementationen jenseits
der Standards
David Decker · deckerweb.de · WP Camp 2012
Selbst Hand anlegenWordPress bringt alles mit!via PHP GettextGettext FunktionenTextdomain laden:
allgemeinPluginsThemesChild Themes
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!
David Decker · deckerweb.de · WP Camp 2012
ImplementierenTextdomain 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()
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!)
David Decker · deckerweb.de · WP Camp 2012
Themes:style.css Kopfbereich, Metadaten:/*
Text Domain: dein-theme-name-slugDomain 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
David Decker · deckerweb.de · WP Camp 2012
ChildThemes:
style.css Kopfbereich, Metadaten:/*
Text Domain: dein-child-theme-slugDomain 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
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 );}
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
David Decker · deckerweb.de · WP Camp 2012
Themes vs. Child Themesget_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
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele IKorrekt:
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' );
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele IIFalsch:
$string = __( $string, 'textdomain' );
$string = __( "Germany consists of $number federalstates", '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
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele IIIErweitert:$string = sprintf( __( 'Germany consists of %d federalstates', 'textdomain' ), $number );
$string = sprintf( _n( 'Germany consists of %d federalstate', '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$dcars', 'textdomain' ), $bike_count, $car_count );
Hinweis: "%1$s" macht Probleme (PHP: $s !!!), daher Single Quotes
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele IVKontext:
$string = _x( 'Frankfurt', 'German city at the riverMain', 'textdomain' );
$string = _x( 'Frankfurt', 'German city at the riverOder', 'textdomain' );
$string = _x( 'Frankfurt', 'an asteroid', 'textdomain');
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele VFormatierungen:
$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 irgendmöglich in den Übersetzungs-Strings!
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele VISicherheit:
Benutzereingaben:
esc_html__()esc_html_e()esc_html_x()
Ausgaben von Text inHTML-Attributen:
esc_attr__()esc_attr_e()esc_attr_x()
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele - Spezial INumerical No-op:
$string = sprintf( _n( 'I have %d bike.', 'You have %dbikes.', $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 );
David Decker · deckerweb.de · WP Camp 2012
Syntaxbeispiele - Spezial IIZahlen & Daten:
number_format_i18n()
date_i18n()
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.
David Decker · deckerweb.de · WP Camp 2012
Best Practices IALLES Ü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!
David Decker · deckerweb.de · WP Camp 2012
Best Practices IIPfadangaben 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... ;-)
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!
David Decker · deckerweb.de · WP Camp 2012
Codestyling Localization
David Decker · deckerweb.de · WP Camp 2012
Codestyling Localization
David Decker · deckerweb.de · WP Camp 2012
GlotPress Installation
David Decker · deckerweb.de · WP Camp 2012
GlotPress Installation
David Decker · deckerweb.de · WP Camp 2012
GlotPress Installation
David Decker · deckerweb.de · WP Camp 2012
PoEdit Editor (poedit.net)
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/
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
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' );
}
}