---
title: "Helper API - Template Functions for Developers - PerfLocale"
description: "Fluent PHP helper API via the perflocale() function for theme and plugin developers — current language, URLs, switcher data, and date formatting."
canonical: "https://perflocale.com/docs/helper-api/"
source: "https://perflocale.com/docs/helper-api/"
format: "markdown"
---
# Helper API

PerfLocale provides a fluent helper API via the `perflocale()` function. This is the recommended way for theme and plugin developers to interact with PerfLocale.

## Quick Start

```php
// Get the helper.
$pl = perflocale();

// Current language info.
echo $pl->slug();        // "fr"
echo $pl->locale();      // "fr_FR"
echo $pl->name();        // "French"
echo $pl->native_name(); // "Français"
echo $pl->display_name(); // "French (Français)"
echo $pl->flag();        // "🇫🇷"
```

## Method Reference

### Language Information

#### `perflocale()->slug(): string`

Returns the current language slug (e.g. `"fr"`). Empty string if no language detected.

#### `perflocale()->locale(): string`

Returns the full locale (e.g. `"fr_FR"`). Falls back to `get_locale()`.

#### `perflocale()->name(): string`

Returns the English name of the current language (e.g. `"French"`).

#### `perflocale()->native_name(): string`

Returns the native name (e.g. `"Français"`). Falls back to the English name.

#### `perflocale()->display_name(): string`

Returns a combined display string: `"French (Français)"`. If English and native names are the same, returns just the name.

#### `perflocale()->flag(): string`

Returns the flag emoji or code (e.g. `"🇫🇷"`).

#### `perflocale()->current_language(): ?object`

Returns the full language object with all properties, or `null` if not detected.

**Language object properties:**

| Property | Type | Example |
| --- | --- | --- |
| slug | string | "fr" |
| locale | string | "fr_FR" |
| name | string | "French" |
| native_name | string | "Français" |
| flag | string | "🇫🇷" |
| text_direction | string | "ltr" |
| is_default | string | 0 |
| is_active | string | 1 |

### Language Checks

#### `perflocale()->is_default(): bool`

Returns `true` if the current language is the default language.

```php
if ( ! perflocale()->is_default() ) {
	// Show "back to English" link.
}
```

#### `perflocale()->is_rtl(): bool`

Returns `true` if the current language is right-to-left (Arabic, Hebrew, etc.).

```php
$dir = perflocale()->is_rtl() ? 'rtl' : 'ltr';
echo '<div dir="' . $dir . '">';
```

#### `perflocale()->is_language( string $slug ): bool`

Check if the current language matches a specific slug.

```php
if ( perflocale()->is_language( 'fr' ) ) {
	echo 'Bienvenue!';
} elseif ( perflocale()->is_language( 'de' ) ) {
	echo 'Willkommen!';
}
```

### Language Data

#### `perflocale()->default_language(): ?object`

Returns the default language object.

```php
$default = perflocale()->default_language();
echo $default->name; // "English"
```

#### `perflocale()->languages(): array`

Returns all active languages as an array of objects.

```php
foreach ( perflocale()->languages() as $lang ) {
	echo $lang->slug . ': ' . $lang->native_name . "\n";
}
// en: English
// fr: Français
// de: Deutsch
```

### URLs

#### `perflocale()->permalink( int $post_id, string $lang_slug ): string`

Get the translated permalink for a post in a specific language.

```php
$de_url = perflocale()->permalink( 42, 'de' );
// https://example.com/de/about/
```

#### `perflocale()->term_link( int $term_id, string $lang_slug ): string`

Get the translated term archive link.

```php
$de_cat = perflocale()->term_link( 5, 'de' );
// https://example.com/de/category/news/
```

#### `perflocale()->home_url( string $lang_slug = '', string $path = '' ): string`

Get the home URL for a specific language.

```php
perflocale()->home_url( 'de' );
// https://example.com/de/

perflocale()->home_url( 'de', '/contact/' );
// https://example.com/de/contact/

perflocale()->home_url();
// Current language home URL.
```

### Translations

#### `perflocale()->translations( int $post_id ): array`

Get all translations of a post as a `[slug => post_id]` map.

```php
$translations = perflocale()->translations( 42 );
// ['en' => 42, 'fr' => 56, 'de' => 78]

foreach ( $translations as $slug => $id ) {
	echo $slug . ': ' . get_the_title( $id ) . "\n";
}
```

#### `perflocale()->translations_many( array $post_ids ): array`

Batch version. Resolves translations for many posts in **two queries total** (one to map ids to translation groups, one to fetch the group rows) regardless of input size — same data shape as `translations()` per source id. Use this on archive / loop templates instead of looping `translations()` per item.

```php
$post_ids = wp_list_pluck( $query->posts, 'ID' );
$siblings = perflocale()->translations_many( $post_ids );

foreach ( $query->posts as $post ) {
	$map = $siblings[ $post->ID ];   // always an array, never missing
	foreach ( $map as $slug => $translation_id ) {
		echo $slug . ': ' . get_the_title( $translation_id ) . "\n";
	}
}
```

Posts with no translations get an empty array for that key (never a missing key), so callers don't need `isset()` guards. Invalid ids (0, negatives, deleted posts) get the same empty-array treatment.

#### `perflocale()->is_translatable( string $name, string $type = 'post_type' ): bool`

Shortcut for "is this post type / taxonomy enabled for translation in **Settings → Translation**?" Saves callers from reaching into the Settings service directly.

```php
if ( perflocale()->is_translatable( 'product' ) ) {
	// Render a "translate this product" CTA.
}

if ( perflocale()->is_translatable( 'product_cat', 'taxonomy' ) ) {
	// Render translatable-term controls.
}
```

Returns `false` for empty names and unknown types, and (defensively) when the settings service isn't reachable — same conservative default the rest of the Helper API uses.

### Locale-aware formatting

#### `perflocale()->format_number( $value, ?string $lang_slug = null, ?int $decimals = null ): string`

Format a number using the current (or specified) language's conventions. Uses PHP's `NumberFormatter` when the `intl` extension is loaded, falls back to `number_format_i18n()` otherwise.

```php
perflocale()->format_number( 1234.56 );          // "1,234.56" in en-US
perflocale()->format_number( 1234.56, 'de' );    // "1.234,56" in de-DE
perflocale()->format_number( 1234.56, 'fr' );    // "1 234,56" in fr-FR
perflocale()->format_number( 1234.5, null, 0 ); // "1,235" (0 decimals)
```

#### `perflocale()->format_currency( $value, string $currency_code, ?string $lang_slug = null ): string`

Locale-aware currency formatting via `NumberFormatter::CURRENCY`. Honours the locale's symbol position, fraction digits, and grouping conventions for the supplied ISO 4217 code.

```php
perflocale()->format_currency( 19.99, 'USD' );        // "$19.99"
perflocale()->format_currency( 19.99, 'EUR', 'de' );  // "19,99 €"
perflocale()->format_currency( 1234, 'JPY' );         // "¥1,234" (zero decimals)
```

Without `intl` loaded, both functions still return useful output (WP's i18n number formatter for `format_number`; `{CODE} {amount}` for `format_currency` — no symbol-guessing). For guaranteed native output, ensure your hosting environment has `ext-intl`.

### Switcher

#### `perflocale()->switcher( array $args = [] ): string`

Returns the language switcher HTML string. Accepts the same snake\_case arguments as the `[perflocale_switcher]` shortcode; any argument omitted falls through to the global **Settings → Language Switcher** value.

```php
echo perflocale()->switcher();

// Inline flags + names in the footer.
echo perflocale()->switcher( [
	'display'      => 'inline',
	'template'     => 'flags_names',
	'hide_current' => true,
] );

// Compact header dropdown: "EN" pill on the button, full native names
// in the options panel, with stacked up + down chevrons.
echo perflocale()->switcher( [
	'display'        => 'dropdown',
	'name_format'    => 'native',
	'trigger_format' => 'slug',
	'arrow_style'    => 'double',
	'class'          => 'site-header__lang',
] );
```

See [Language Switcher](https://perflocale.com/docs/language-switcher/) for the full argument list. The [per-instance attribute coverage matrix](https://perflocale.com/docs/language-switcher/#per-instance-attribute-coverage) shows how the same arguments are exposed on every other rendering surface (block, widget, shortcode, Customizer floating, theme addons, page-builder integrations).

#### `perflocale()->current_url( string $lang_slug ): string`

Returns the URL of the current page in another language — the same canonical URL the bundled switcher and hreflang tags use. On singular pages where the target language has no translation, returns an empty string so callers can fall through to `perflocale()->home_url( $slug )` or render an “untranslated” UI as they prefer.

```php
if ( $de_url = perflocale()->current_url( 'de' ) ) {
	echo '<a href="' . esc_url( $de_url ) . '">Deutsch</a>';
}
```

#### `perflocale()->switcher_links(): array`

Returns a structured array of switcher items for the current page — the same data the bundled switcher renders, exposed so themes can build their own markup without re-implementing URL conversion or translation-availability checks. Languages without a translation on the current singular page are still included with `is_translated => false` and an empty `url`; themes that want the bundled switcher’s hide-untranslated behaviour can filter on that flag.

Each entry has the following keys:

| Key | Type | Example |
| --- | --- | --- |
| slug | string | "fr" |
| locale | string | "fr_FR" |
| name | string | "French" |
| native_name | string | "Français" |
| flag | string | "🇫🇷" |
| text_direction | string | "ltr" |
| url | string | "https://example.com/fr/about/" |
| is_current | bool | false |
| is_translated | bool | true |

```php
<ul class="my-lang-switcher">
<?php foreach ( perflocale()->switcher_links() as $link ) : ?>
	<li class="<?php echo $link['is_current'] ? 'is-current' : ''; ?>">
		<?php if ( $link['is_translated'] ) : ?>
			<a href="<?php echo esc_url( $link['url'] ); ?>" hreflang="<?php echo esc_attr( $link['slug'] ); ?>">
				<?php echo esc_html( $link['flag'] . ' ' . $link['native_name'] ); ?>
			</a>
		<?php else : ?>
			<span class="is-untranslated"><?php echo esc_html( $link['native_name'] ); ?></span>
		<?php endif; ?>
	</li>
<?php endforeach; ?>
</ul>
```

### Date & Time

Each language can override the site’s `date_format` / `time_format` from **PerfLocale → Languages**. These helpers return the active language’s resolved format, falling back to the site default when no override is set. Filterable via [`perflocale/date_format`](https://perflocale.com/docs/hooks/#perflocale-date-format) and [`perflocale/time_format`](https://perflocale.com/docs/hooks/#perflocale-time-format).

#### `perflocale()->date_format(): string`

Returns the PHP date-format string for the current language (e.g. `"j F Y"`).

```php
echo wp_date( perflocale()->date_format(), get_post_time( 'U' ) );
```

#### `perflocale()->time_format(): string`

Returns the PHP time-format string for the current language (e.g. `"H:i"`).

#### `perflocale()->datetime_format(): string`

Combined date + time format — the two strings joined with a single space.

#### `perflocale()->format_date( int|string|null $timestamp = null ): string`

Render a timestamp in the active language. Accepts a Unix int, a `strtotime()`\-parseable string, or `null` for “now”. Returns an empty string if the input can’t be parsed. Wraps `wp_date()` so month and day names are localized too.

```php
echo perflocale()->format_date( get_post_time( 'U' ) );
// French: "13 mai 2026"
// English: "May 13, 2026"
```

#### `perflocale()->format_time( int|string|null $timestamp = null ): string`

Same as `format_date()` but applies the time format.

#### `perflocale()->format_datetime( int|string|null $timestamp = null ): string`

Combined date + time render in the active language.

## Service Container Access

For advanced use cases, the service container is reachable via `\PerfLocale\Plugin::get_instance()`:

```php
$plugin = \PerfLocale\Plugin::get_instance();

$router     = $plugin->get( 'router' );
$settings   = $plugin->get( 'settings' );
$cache      = $plugin->get( 'cache' );
$converter  = $plugin->get( 'url_converter' );
```

## Template Tags

These standalone functions are available for backward compatibility:

| Function | Description |
| --- | --- |
| perflocale_language_switcher( $args ) | Echo the language switcher |
| perflocale_get_language_switcher( $args ) | Return the language switcher HTML |
| perflocale_current_language() | Get current language object |
| perflocale_get_languages() | Get all active languages |
| perflocale_get_permalink( $id, $slug ) | Get translated post URL |
| perflocale_get_term_link( $id, $slug ) | Get translated term URL |
| perflocale_home_url( $slug, $path ) | Get language home URL |
| perflocale_current_url( $slug ) | Current page’s URL in another language (empty when untranslated) |
| perflocale_switcher_links() | Structured switcher items — same shape as perflocale()->switcher_links() |
| perflocale_is_rtl() | Check if current language is RTL |
| perflocale_if_language( $langs, $invert = false ) | Conditional — true when the current language matches (single slug, comma-separated string, or array). Same predicate that backs the Gutenberg block and [perflocale_if] shortcode. |
| perflocale_t( $key, $context = '' ) | Translate a string registered under the perflocale domain. Returns the original key if no translation is found. |
| perflocale_date_format() | Date format for the current language |
| perflocale_time_format() | Time format for the current language |
| perflocale_format_date( $timestamp = null ) | Render a timestamp as a date in the current language |
| perflocale_format_time( $timestamp = null ) | Render a timestamp as a time in the current language |
| perflocale_format_datetime( $timestamp = null ) | Render a timestamp as date + time in the current language |
| perflocale_hreflang_tags() | Output hreflang tags manually |

## Examples

### Conditional content by language

```php
if ( perflocale()->is_language( 'fr' ) ) {
	get_template_part( 'partials/hero', 'fr' );
} else {
	get_template_part( 'partials/hero' );
}
```

### Custom language menu

```php
<ul class="lang-menu">
<?php foreach ( perflocale()->languages() as $lang ) : ?>
	<li class="<?php echo perflocale()->is_language( $lang->slug ) ? 'active' : ''; ?>">
		<a href="/<?php echo esc_url( perflocale()->home_url( $lang->slug ) ); ?>">
			<?php echo esc_html( $lang->native_name ); ?>
		</a>
	</li>
<?php endforeach; ?>
</ul>
```

### Show translation links for current post

```php
<?php
$translations = perflocale()->translations( get_the_ID() );
foreach ( $translations as $slug => $post_id ) :
	if ( $post_id === get_the_ID() ) continue;
?>
	<a href="/<?php echo esc_url( get_permalink( $post_id ) ); ?>">
		Read in <?php echo esc_html( strtoupper( $slug ) ); ?>
	</a>
<?php endforeach; ?>
```
