Skip to content

Powered by Grav CMS + Helios Theme

Translating KahunaCart

This page is for translators. It covers translating KahunaCart's text (the storefront, checkout, emails and subjects, and admin labels and help) and contributing those translations for other stores to use.

If you only need your catalog in two languages, see Multilanguage instead.

Before you begin

  • A checkout of the plugin, or a store you can drop a file into at user/plugins/kahunacart/languages/.
  • Grav's language code for the language you are writing, such as de, fr or pt-br.

What is translated where

What Where it lives Who translates it
Product, category, tag, attribute, option, shipping, tax and sale text The store's own database, per language The merchant, in the admin
Everything KahunaCart itself says languages/<code>.yaml in the plugin You, once, for every store
The merchant's config strings, such as invoice.footer, offline.instructions or an address format kahunacart.yaml The merchant

This page is about the middle row. languages/en.yaml is the source; every string in the plugin goes through Grav's |t filter against a key in it. A language pack is a second file beside it with the same keys.

How a pack loads

Grav reads every <code>.yaml in a plugin's languages/ directory and treats the file name as the language. Copy de.yaml in, run bin/grav clear-cache, and a storefront on /de renders in German. No additional setting, code or registration is required.

A key the pack does not carry falls back to English, per key. A partial German pack still loads, with untranslated strings shown in English.

The lookup chain for a string on /de, with de and en both configured: de.yaml, then the site's fallback languages in order, then en.yaml, then the key itself. A string that shows as PLUGIN_KAHUNACART.SOMETHING on a page is missing from every file, including the source. Report it.

The key namespaces

Every key is under PLUGIN_KAHUNACART. Within it the prefixes say what a string is for.

Prefix Used by Notes
EMAIL_* The sixteen emails, subjects included Subjects carry the order number as %s. Keep the placeholder and move it where the sentence wants it
NOTIFICATION_* The Notifications screen A label and a _DESCRIPTION per message
OBJECT_TEMPLATE_* The Object templates screen Labels and help
ADDRESS_*, CHECKOUT_*, CART_* The storefront Short. These sit on buttons and beside fields
TAB_*, *_SECTION, *_HELP The plugin's settings blueprint Help text may contain simple HTML, which the admin renders
QUOTE_*, PAY_*, ORDER_* The customer's order pages

Keys ending _HELP are the long ones. Translate the meaning; use a faithful paraphrase where a literal translation would be unclear.

Do not translate the keys, the %s and %d placeholders, or anything inside backticks or <code>. Those are config key names and file paths a merchant types.

Plural forms and ICU

Grav supports both the flat %s style and ICU message syntax. KahunaCart's source uses flat placeholders throughout. Every argument is positional, so a translation can reorder them.

Where your language needs a plural form the English does not, write the ICU form for that key. Grav's translator understands both in the same file.

Translate a pack

  1. Run bin/plugin kahunacart lang:export --status to see which languages exist and how complete each is.
  2. Copy languages/en.yaml to languages/<code>.yaml, using Grav's code for the language.
  3. Translate the values, leaving the keys and placeholders as they are. Delete any key you have not translated rather than leaving it in English, so the fallback and the coverage figure stay accurate.
  4. Run bin/plugin kahunacart lang:export --status --missing=<code> to list what is still untranslated.

Test a pack on your own store

  1. Add the language to user/config/system.yaml under languages.supported.
  2. Run bin/grav clear-cache.
  3. Open /<code>/shop, add something to the cart, and walk through checkout.
  4. Place an order and run bin/plugin kahunacart work. The confirmation email renders in the order's language, subject included.
  5. Open the plugin's settings page in the admin with the admin language set to yours.

The storefront, the emails and the admin read the same file, so all three change together.

Submit a pack

The community translation project runs on Crowdin. crowdin.yml at the repository root is its configuration: languages/en.yaml is the source and each language downloads to languages/<code>.yaml.

Until the maintainer opens the project, a pull request adding languages/<code>.yaml is the whole submission. Put the lang:export --status output in the description to say how complete it is.

Once the project is open, translate in Crowdin's editor. The maintainer pulls the files with crowdin download before a release and uploads the source with bin/plugin kahunacart lang:export - | crowdin upload sources, which is the same file with comments stripped.

A pack ships in the next release once the maintainer is comfortable calling it supported. A partial pack is still merged and still loads, and the release notes say how complete it is.

The lang:export command

Form Does
bin/plugin kahunacart lang:export Print the source as YAML with its comments stripped, for upload
bin/plugin kahunacart lang:export out.yaml Write it to a file
bin/plugin kahunacart lang:export --format=json The same as a flat key-to-string JSON map
bin/plugin kahunacart lang:export --status One row per pack: translated, missing and stale key counts
bin/plugin kahunacart lang:export --status --missing=de The keys de.yaml has not translated, and any it carries that the source no longer does

A key whose English value is blank on purpose (a default the merchant fills in) does not count as a string to translate.