WordPress Plugins und Themes übersetzbar machen - die Grundprinzipien, Grundfunktionen, hilfreiche Tipps, Tricks, Erfahrungen, häufige Fehler und Best Practices
2. 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
David Decker · deckerweb.de · WP Camp 2012
3. Selbst Hand anlegen
WordPress bringt alles mit!
via PHP Gettext
Gettext Funktionen
Textdomain laden:
allgemein
Plugins
Themes
Child Themes
David Decker · deckerweb.de · WP Camp 2012
4. 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
7. style.css Kopfbereich, Metadaten:
Themes:
/*
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
David Decker · deckerweb.de · WP Camp 2012
8. style.css Kopfbereich, Metadaten:
Child
/*
Text Domain: dein-child-theme-slug
Domain Path: rel-sprachdatei-pfad
Themes: */
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
9. 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
10. Plugins vs. Themes:
Dateinamen der Sprachdateien
Themes: Plugins:
de_DE.mo /.po deine-textdomain-de_DE.mo /.po
nl_NL.mo /.po deine-textdomain-nl_NL.mo /.po
fi.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
11. 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
David Decker · deckerweb.de · WP Camp 2012
12. 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' );
David Decker · deckerweb.de · WP Camp 2012
13. Immer:
Single Quotes!
Syntaxbeispiele II EINE (1) Textdomain:
String in Single Quotes
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' );
David Decker · deckerweb.de · WP Camp 2012
14. 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
David Decker · deckerweb.de · WP Camp 2012
15. 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'
);
David Decker · deckerweb.de · WP Camp 2012
16. 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!
David Decker · deckerweb.de · WP Camp 2012
17. Syntaxbeispiele VI
Sicherheit:
Benutzereingaben: Ausgaben von Text in
HTML-Attributen:
esc_html__()
esc_html_e() esc_attr__()
esc_html_x() esc_attr_e()
esc_attr_x()
David Decker · deckerweb.de · WP Camp 2012
18. 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 );
David Decker · deckerweb.de · WP Camp 2012
19. Syntaxbeispiele - Spezial II
Zahlen & Daten:
number_format_i18n()
date_i18n()
David Decker · deckerweb.de · WP Camp 2012
20. 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
21. 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!
David Decker · deckerweb.de · WP Camp 2012
22. 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... ;-)
David Decker · deckerweb.de · WP Camp 2012