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,frorpt-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
- Run
bin/plugin kahunacart lang:export --statusto see which languages exist and how complete each is. - Copy
languages/en.yamltolanguages/<code>.yaml, using Grav's code for the language. - 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.
- Run
bin/plugin kahunacart lang:export --status --missing=<code>to list what is still untranslated.
Test a pack on your own store
- Add the language to
user/config/system.yamlunderlanguages.supported. - Run
bin/grav clear-cache. - Open
/<code>/shop, add something to the cart, and walk through checkout. - Place an order and run
bin/plugin kahunacart work. The confirmation email renders in the order's language, subject included. - 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.