A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.
CN codes are the EU's 8-digit goods classification system used for international trade, customs declarations, and trade statistics. This library provides:
- Complete CN code database (2023, 2024, 2025, 2026)
- Five-level hierarchy: Sections, Chapters, Headings, Subheadings, CN Codes
- Lazy loading per version — only the requested year's data is loaded into memory
- Supplementary unit information on CN codes
- Framework-agnostic translation system with 23 language support
- Adapters for Symfony, Laravel, and native PHP
- Zero runtime dependencies for the core library
composer require xterr/php-cncodesuseXterr\CnCodes\CnCodesFactory;
useXterr\CnCodes\CnVersion;
$factory = newCnCodesFactory();
$codes = $factory->getCodes();
// Find a specific CN code$cnCode = $codes->getByCodeAndVersion('01012100', CnVersion::VERSION_2026);
echo$cnCode->getCode(); // "01012100"echo$cnCode->getRawCode(); // "0101 21 00"echo$cnCode->getName(); // "Pure-bred breeding animals" (English)echo$cnCode->getLocalName(); // "Pure-bred breeding animals" (falls back to English)echo$cnCode->getSection(); // "I"echo$cnCode->getChapter(); // "01"echo$cnCode->getHeading(); // "0101"echo$cnCode->getSupplementaryUnit(); // "PST"useXterr\CnCodes\CnCodesFactory;
useXterr\CnCodes\CnVersion;
useXterr\CnCodes\Translation\Adapter\ArrayTranslator;
// Use the built-in ArrayTranslator for zero-dependency translations$translator = newArrayTranslator(null, 'de');
$factory = newCnCodesFactory(null, $translator);
$section = $factory->getSections()->getByCodeAndVersion('I', CnVersion::VERSION_2026);
echo$section->getName(); // "LIVE ANIMALS; ANIMAL PRODUCTS" (always English)echo$section->getLocalName(); // "LEBENDE TIERE UND WAREN TIERISCHEN URSPRUNGS" (German translation)The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.
Best for standalone PHP applications or when you don't want any framework dependencies.
useXterr\CnCodes\CnCodesFactory;
useXterr\CnCodes\Translation\Adapter\ArrayTranslator;
// Simple usage with locale$translator = newArrayTranslator(null, 'fr');
$factory = newCnCodesFactory(null, $translator);
// With fallback locale$translator = newArrayTranslator(null, 'fr', 'en');
// Change locale at runtime$translator->setLocale('de');
// Get available locales$locales = $translator->getAvailableLocales();
// ['bg', 'cs', 'da', 'de', 'el', 'es', 'et', 'fi', 'fr', 'ga', 'hr', 'hu', 'it', 'lt', 'lv', 'mt', 'nl', 'pl', 'pt', 'ro', 'sk', 'sl', 'sv']For Symfony applications. Requires symfony/translation-contracts.
composer require symfony/translation-contractsuseXterr\CnCodes\CnCodesFactory;
useXterr\CnCodes\Translation\Adapter\SymfonyTranslatorAdapter;
useSymfony\Contracts\Translation\TranslatorInterface;
// In a Symfony controller or servicepublicfunction__construct(
TranslatorInterface$symfonyTranslator
) {
$adapter = newSymfonyTranslatorAdapter($symfonyTranslator);
$this->cnCodesFactory = newCnCodesFactory(null, $adapter);
}
// Usage$codes = $this->cnCodesFactory->getCodes();
$cnCode = $codes->getByCodeAndVersion('01012100');
// Uses the locale from Symfony's translator (auto-detected from request)echo$cnCode->getLocalName();Copy or generate translation files to your Symfony translations directory:
# Generate YAML files for Symfony
php bin/console cn:translations:build yaml-generate
# Copy to your Symfony project
cp Resources/translations/yaml/cnCodes.*.yaml /path/to/symfony/translations/Or configure as a translation resource in config/packages/translation.yaml:
framework:
translator:
paths:
- '%kernel.project_dir%/vendor/xterr/php-cncodes/Resources/translations'For Laravel applications. Requires illuminate/contracts.
composer require illuminate/contractsuseXterr\CnCodes\CnCodesFactory;
useXterr\CnCodes\Translation\Adapter\LaravelTranslatorAdapter;
useIlluminate\Contracts\Translation\Translator;
// In a Laravel service providerpublicfunctionregister()
{
$this->app->singleton(CnCodesFactory::class, function ($app) {
$adapter = newLaravelTranslatorAdapter($app->make(Translator::class));
returnnewCnCodesFactory(null, $adapter);
});
}
// Usage in controllerpublicfunctionshow(CnCodesFactory$factory, string$code)
{
$cnCode = $factory->getCodes()->getByCodeAndVersion($code);
// Uses Laravel's current localereturnresponse()->json([
'code' => $cnCode->getCode(),
'name' => $cnCode->getName(),
'localName' => $cnCode->getLocalName(),
]);
}Generate and publish Laravel translation files:
# Generate Laravel PHP files
php bin/console cn:translations:build all
# Copy to your Laravel project
cp -r Resources/translations/laravel/cncodes /path/to/laravel/lang/vendor/Returns the original English text. Used internally as the default when no translator is provided.
useXterr\CnCodes\Translation\Adapter\NullTranslator;
$translator = newNullTranslator();
echo$translator->translate('Pure-bred breeding animals'); // "Pure-bred breeding animals"Implement the TranslatorInterface for custom translation sources:
useXterr\CnCodes\Translation\TranslatorInterface;
class DatabaseTranslator implements TranslatorInterface
{
publicfunctiontranslate(string$id, ?string$locale = null, string$domain = 'cnCodes'): string
{
// Your custom translation logicreturn$this->repository->findTranslation($id, $locale) ?? $id;
}
}The library includes translations for 23 EU languages:
| Code | Language | Code | Language |
|---|---|---|---|
| bg | Bulgarian | it | Italian |
| cs | Czech | lt | Lithuanian |
| da | Danish | lv | Latvian |
| de | German | mt | Maltese |
| el | Greek | nl | Dutch |
| es | Spanish | pl | Polish |
| et | Estonian | pt | Portuguese |
| fi | Finnish | ro | Romanian |
| fr | French | sk | Slovak |
| ga | Irish | sl | Slovenian |
| hr | Croatian | sv | Swedish |
| hu | Hungarian |
| Method | Return Type | Description |
|---|---|---|
getCode() | string | Normalized code (e.g., "01012100") |
getRawCode() | string | Space-separated code (e.g., "0101 21 00") |
getName() | string | English name |
getLocalName() | string | Translated name (falls back to English) |
getVersion() | int | Version year (2023, 2024, 2025, or 2026) |
getSection() | ?string | Parent section (e.g., "I") |
getChapter() | ?string | Parent chapter (e.g., "01") |
getHeading() | ?string | Parent heading (e.g., "0101") |
getSubheading() | ?string | Parent subheading (e.g., "010121") or null |
getSupplementaryUnit() | ?string | Supplementary unit code (e.g., "PST", "KGM") or null |
The Combined Nomenclature follows a five-level hierarchy:
Section (I-XXI) — 21 broad categories
└─ Chapter (01-97) — 97 product groups
└─ Heading (4-digit) — ~957 product types
└─ Subheading (6-digit) — ~1,830 HS subheadings
└─ CN Code (8-digit) — ~9,790 specific goods
CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026$factory = newCnCodesFactory();
$codes = $factory->getCodes();
// Iterate all codes (loads all versions)foreach ($codesas$cnCode) {
echo$cnCode->getCode() . ': ' . $cnCode->getLocalName() . "\n";
}
// Count total codes across all versionsechocount($codes); // ~39,087 codes// Get codes for a specific version only$codes2026 = $codes->getAllByVersion(CnVersion::VERSION_2026);
echocount($codes2026); // 9,791 codes// Convert to array$array = $codes->toArray();CN classification data is sourced from the official EU Vocabularies (RDF/XML format), published by the Publications Office of the European Union.
Individual datasets can be downloaded per year:
- Combined Nomenclature 2026
- Combined Nomenclature 2025
- Combined Nomenclature 2024
- Combined Nomenclature 2023
The library includes console commands to build translation files in different formats.
# Build all formats
composer translations:build
# Build specific formats
composer translations:php # PHP arrays (source of truth)
composer translations:yaml # Symfony YAML format
composer translations:laravel # Laravel PHP formatFor Symfony API Platform, expose CpvCode with the localName property:
# config/api_platform/cn_code.yamlXterr\CnCodes\CnCode:
attributes:
normalization_context:
groups: [ 'cn_code:read' ]properties:
code:
groups: [ 'cn_code:read' ]name:
groups: [ 'cn_code:read' ]localName:
groups: [ 'cn_code:read' ]version:
groups: [ 'cn_code:read' ]section:
groups: [ 'cn_code:read' ]heading:
groups: [ 'cn_code:read' ]subheading:
groups: [ 'cn_code:read' ]supplementaryUnit:
groups: [ 'cn_code:read' ]composer install
./vendor/bin/phpunit- PHP >= 8.0
- ext-json
symfony/translation-contracts- For Symfony integrationilluminate/contracts- For Laravel integrationsymfony/console+symfony/yaml+sweetrdf/easyrdf- For CLI data generation (dev only)
This library is licensed under the MIT License. See the LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.
- Razvan Ceana - Author
- CN code data sourced from the EU Vocabularies