Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

PHP CN Codes

PHP VersionLicenseLatest Version

A framework-agnostic PHP library for working with CN (Combined Nomenclature) codes, including built-in translation support for 23 EU languages.

Overview

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

Installation

composer require xterr/php-cncodes

Quick Start

Basic Usage (No Translation)

useXterr\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"

With Translation Support

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)

Translation Adapters

The library provides a framework-agnostic TranslatorInterface with multiple adapter implementations.

ArrayTranslator (Native PHP - Zero Dependencies)

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']

SymfonyTranslatorAdapter

For Symfony applications. Requires symfony/translation-contracts.

composer require symfony/translation-contracts
useXterr\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();

Symfony Configuration

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'

LaravelTranslatorAdapter

For Laravel applications. Requires illuminate/contracts.

composer require illuminate/contracts
useXterr\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(),
]);
}

Laravel Configuration

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/

NullTranslator (Default)

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"

Custom Translator

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;
}
}

Supported Languages

The library includes translations for 23 EU languages:

CodeLanguageCodeLanguage
bgBulgarianitItalian
csCzechltLithuanian
daDanishlvLatvian
deGermanmtMaltese
elGreeknlDutch
esSpanishplPolish
etEstonianptPortuguese
fiFinnishroRomanian
frFrenchskSlovak
gaIrishslSlovenian
hrCroatiansvSwedish
huHungarian

CnCode Properties

MethodReturn TypeDescription
getCode()stringNormalized code (e.g., "01012100")
getRawCode()stringSpace-separated code (e.g., "0101 21 00")
getName()stringEnglish name
getLocalName()stringTranslated name (falls back to English)
getVersion()intVersion year (2023, 2024, 2025, or 2026)
getSection()?stringParent section (e.g., "I")
getChapter()?stringParent chapter (e.g., "01")
getHeading()?stringParent heading (e.g., "0101")
getSubheading()?stringParent subheading (e.g., "010121") or null
getSupplementaryUnit()?stringSupplementary unit code (e.g., "PST", "KGM") or null

CN Hierarchy

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

CN Versions

CnVersion::VERSION_2023// 2023
CnVersion::VERSION_2024// 2024
CnVersion::VERSION_2025// 2025
CnVersion::VERSION_2026// 2026

Iterating Over Codes

$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();

Data Source

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:

Building Translation Files

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 format

API Platform Integration

For 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' ]

Testing

composer install
./vendor/bin/phpunit

Requirements

  • PHP >= 8.0
  • ext-json

Optional Dependencies

  • symfony/translation-contracts - For Symfony integration
  • illuminate/contracts - For Laravel integration
  • symfony/console + symfony/yaml + sweetrdf/easyrdf - For CLI data generation (dev only)

License

This library is licensed under the MIT License. See the LICENSE file for details.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Credits

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages