| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345 |
- <?php
- namespace PhpOffice\PhpSpreadsheetInfra;
- use Exception;
- use PhpOffice\PhpSpreadsheet\Cell\Cell;
- use PhpOffice\PhpSpreadsheet\IOFactory;
- use PhpOffice\PhpSpreadsheet\Spreadsheet;
- use PhpOffice\PhpSpreadsheet\Worksheet\Column;
- use PhpOffice\PhpSpreadsheet\Worksheet\Row;
- use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
- class LocaleGenerator
- {
- private const EXCEL_LOCALISATION_WORKSHEET = 'Excel Localisation';
- private const EXCEL_FUNCTIONS_WORKSHEET = 'Excel Functions';
- private const LOCALE_NAME_ROW = 1;
- private const LOCALE_LANGUAGE_NAME_ROW = 2;
- private const ENGLISH_LANGUAGE_NAME_ROW = 3;
- private const ARGUMENT_SEPARATOR_ROW = 5;
- private const ERROR_CODES_FIRST_ROW = 8;
- private const FUNCTION_NAME_LIST_FIRST_ROW = 4;
- private const ENGLISH_FUNCTION_CATEGORIES_COLUMN = 'A';
- private const ENGLISH_REFERENCE_COLUMN = 'B';
- private const EOL = "\n"; // not PHP_EOL
- /**
- * @var string
- */
- protected $translationSpreadsheetName;
- /**
- * @var string
- */
- protected $translationBaseFolder;
- protected $phpSpreadsheetFunctions;
- /**
- * @var Spreadsheet
- */
- protected $translationSpreadsheet;
- protected $verbose;
- /**
- * @var Worksheet
- */
- protected $localeTranslations;
- protected $localeLanguageMap = [];
- protected $errorCodeMap = [];
- /**
- * @var Worksheet
- */
- private $functionNameTranslations;
- protected $functionNameLanguageMap = [];
- protected $functionNameMap = [];
- public function __construct(
- string $translationBaseFolder,
- string $translationSpreadsheetName,
- array $phpSpreadsheetFunctions,
- bool $verbose = false
- ) {
- $this->translationBaseFolder = $translationBaseFolder;
- $this->translationSpreadsheetName = $translationSpreadsheetName;
- $this->phpSpreadsheetFunctions = $phpSpreadsheetFunctions;
- $this->verbose = $verbose;
- }
- public function generateLocales(): void
- {
- $this->openTranslationWorkbook();
- $this->localeTranslations = $this->getTranslationSheet(self::EXCEL_LOCALISATION_WORKSHEET);
- $this->localeLanguageMap = $this->mapLanguageColumns($this->localeTranslations);
- $this->mapErrorCodeRows();
- $this->functionNameTranslations = $this->getTranslationSheet(self::EXCEL_FUNCTIONS_WORKSHEET);
- $this->functionNameLanguageMap = $this->mapLanguageColumns($this->functionNameTranslations);
- $this->mapFunctionNameRows();
- foreach ($this->localeLanguageMap as $column => $locale) {
- $this->buildConfigFileForLocale($column, $locale);
- }
- foreach ($this->functionNameLanguageMap as $column => $locale) {
- $this->buildFunctionsFileForLocale($column, $locale);
- }
- }
- protected function buildConfigFileForLocale($column, $locale): void
- {
- $language = $this->localeTranslations->getCell($column . self::ENGLISH_LANGUAGE_NAME_ROW)->getValue();
- $localeLanguage = $this->localeTranslations->getCell($column . self::LOCALE_LANGUAGE_NAME_ROW)->getValue();
- $configFile = $this->openConfigFile($locale, $language, $localeLanguage);
- $this->writeConfigArgumentSeparator($configFile, $column);
- $this->writeFileSectionHeader($configFile, 'Error Codes');
- foreach ($this->errorCodeMap as $errorCode => $row) {
- $translationCell = $this->localeTranslations->getCell($column . $row);
- $translationValue = $translationCell->getValue();
- if (!empty($translationValue)) {
- $errorCodeTranslation = "{$errorCode} = {$translationValue}" . self::EOL;
- fwrite($configFile, $errorCodeTranslation);
- } else {
- $errorCodeTranslation = "{$errorCode}" . self::EOL;
- fwrite($configFile, $errorCodeTranslation);
- $this->log("No {$language} translation available for error code {$errorCode}");
- }
- }
- fclose($configFile);
- }
- protected function writeConfigArgumentSeparator($configFile, $column): void
- {
- $translationCell = $this->localeTranslations->getCell($column . self::ARGUMENT_SEPARATOR_ROW);
- $localeValue = $translationCell->getValue();
- if (!empty($localeValue)) {
- $functionTranslation = "ArgumentSeparator = {$localeValue}" . self::EOL;
- fwrite($configFile, $functionTranslation);
- } else {
- $this->log('No Argument Separator defined');
- }
- }
- protected function buildFunctionsFileForLocale($column, $locale): void
- {
- $language = $this->functionNameTranslations->getCell($column . self::ENGLISH_LANGUAGE_NAME_ROW)->getValue();
- $localeLanguage = $this->functionNameTranslations->getCell($column . self::LOCALE_LANGUAGE_NAME_ROW)
- ->getValue();
- $functionFile = $this->openFunctionNameFile($locale, $language, $localeLanguage);
- foreach ($this->functionNameMap as $functionName => $row) {
- $translationCell = $this->functionNameTranslations->getCell($column . $row);
- $translationValue = $translationCell->getValue();
- if ($this->isFunctionCategoryEntry($translationCell)) {
- $this->writeFileSectionHeader($functionFile, "{$translationValue} ({$functionName})");
- } elseif (!array_key_exists($functionName, $this->phpSpreadsheetFunctions) && substr($functionName, 0, 1) !== '*') {
- $this->log("Function {$functionName} is not defined in PhpSpreadsheet");
- } elseif (!empty($translationValue)) {
- $functionTranslation = "{$functionName} = {$translationValue}" . self::EOL;
- fwrite($functionFile, $functionTranslation);
- } else {
- $this->log("No {$language} translation available for function {$functionName}");
- }
- }
- fclose($functionFile);
- }
- protected function openConfigFile(string $locale, string $language, string $localeLanguage)
- {
- $this->log("Building locale {$locale} ($language) configuration");
- $localeFolder = $this->getLocaleFolder($locale);
- $configFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'config');
- $this->log("Writing locale configuration to {$configFileName}");
- $configFile = fopen($configFileName, 'wb');
- $this->writeFileHeader($configFile, $localeLanguage, $language, 'locale settings');
- return $configFile;
- }
- protected function openFunctionNameFile(string $locale, string $language, string $localeLanguage)
- {
- $this->log("Building locale {$locale} ($language) function names");
- $localeFolder = $this->getLocaleFolder($locale);
- $functionFileName = realpath($localeFolder . DIRECTORY_SEPARATOR . 'functions');
- $this->log("Writing local function names to {$functionFileName}");
- $functionFile = fopen($functionFileName, 'wb');
- $this->writeFileHeader($functionFile, $localeLanguage, $language, 'function name translations');
- return $functionFile;
- }
- protected function getLocaleFolder(string $locale): string
- {
- $localeFolder = $this->translationBaseFolder .
- DIRECTORY_SEPARATOR .
- str_replace('_', DIRECTORY_SEPARATOR, $locale);
- if (!file_exists($localeFolder) || !is_dir($localeFolder)) {
- mkdir($localeFolder, 0777, true);
- }
- return $localeFolder;
- }
- protected function writeFileHeader($localeFile, string $localeLanguage, string $language, string $title): void
- {
- fwrite($localeFile, str_repeat('#', 60) . self::EOL);
- fwrite($localeFile, '##' . self::EOL);
- fwrite($localeFile, "## PhpSpreadsheet - {$title}" . self::EOL);
- fwrite($localeFile, '##' . self::EOL);
- fwrite($localeFile, "## {$localeLanguage} ({$language})" . self::EOL);
- fwrite($localeFile, '##' . self::EOL);
- fwrite($localeFile, str_repeat('#', 60) . self::EOL . self::EOL);
- }
- protected function writeFileSectionHeader($localeFile, string $header): void
- {
- fwrite($localeFile, self::EOL . '##' . self::EOL);
- fwrite($localeFile, "## {$header}" . self::EOL);
- fwrite($localeFile, '##' . self::EOL);
- }
- protected function openTranslationWorkbook(): void
- {
- $filepathName = $this->translationBaseFolder . '/' . $this->translationSpreadsheetName;
- $this->translationSpreadsheet = IOFactory::load($filepathName);
- }
- protected function getTranslationSheet(string $sheetName): Worksheet
- {
- $worksheet = $this->translationSpreadsheet->setActiveSheetIndexByName($sheetName);
- if ($worksheet === null) {
- throw new Exception("{$sheetName} Worksheet not found");
- }
- return $worksheet;
- }
- protected function mapLanguageColumns(Worksheet $translationWorksheet): array
- {
- $sheetName = $translationWorksheet->getTitle();
- $this->log("Mapping Languages for {$sheetName}:");
- $baseColumn = self::ENGLISH_REFERENCE_COLUMN;
- $languagesList = $translationWorksheet->getColumnIterator(++$baseColumn);
- $languageNameMap = [];
- foreach ($languagesList as $languageColumn) {
- /** @var Column $languageColumn */
- $cells = $languageColumn->getCellIterator(self::LOCALE_NAME_ROW, self::LOCALE_NAME_ROW);
- $cells->setIterateOnlyExistingCells(true);
- foreach ($cells as $cell) {
- /** @var Cell $cell */
- if ($this->localeCanBeSupported($translationWorksheet, $cell)) {
- $languageNameMap[$cell->getColumn()] = $cell->getValue();
- $this->log($cell->getColumn() . ' -> ' . $cell->getValue());
- }
- }
- }
- return $languageNameMap;
- }
- protected function localeCanBeSupported(Worksheet $worksheet, Cell $cell): bool
- {
- if ($worksheet->getTitle() === self::EXCEL_LOCALISATION_WORKSHEET) {
- // Only provide support for languages that have a function argument separator defined
- // in the localisation worksheet
- return !empty(
- $worksheet->getCell($cell->getColumn() . self::ARGUMENT_SEPARATOR_ROW)->getValue()
- );
- }
- // If we're processing other worksheets, then language support is determined by whether we included the
- // language in the map when we were processing the localisation worksheet (which is always processed first)
- return in_array($cell->getValue(), $this->localeLanguageMap, true);
- }
- protected function mapErrorCodeRows(): void
- {
- $this->log('Mapping Error Codes:');
- $errorList = $this->localeTranslations->getRowIterator(self::ERROR_CODES_FIRST_ROW);
- foreach ($errorList as $errorRow) {
- /** @var Row $errorList */
- $cells = $errorRow->getCellIterator(self::ENGLISH_REFERENCE_COLUMN, self::ENGLISH_REFERENCE_COLUMN);
- $cells->setIterateOnlyExistingCells(true);
- foreach ($cells as $cell) {
- /** @var Cell $cell */
- if ($cell->getValue() != '') {
- $this->log($cell->getRow() . ' -> ' . $cell->getValue());
- $this->errorCodeMap[$cell->getValue()] = $cell->getRow();
- }
- }
- }
- }
- protected function mapFunctionNameRows(): void
- {
- $this->log('Mapping Functions:');
- $functionList = $this->functionNameTranslations->getRowIterator(self::FUNCTION_NAME_LIST_FIRST_ROW);
- foreach ($functionList as $functionRow) {
- /** @var Row $functionRow */
- $cells = $functionRow->getCellIterator(self::ENGLISH_REFERENCE_COLUMN, self::ENGLISH_REFERENCE_COLUMN);
- $cells->setIterateOnlyExistingCells(true);
- foreach ($cells as $cell) {
- /** @var Cell $cell */
- if ($this->isFunctionCategoryEntry($cell)) {
- if (!empty($cell->getValue())) {
- $this->log('CATEGORY: ' . $cell->getValue());
- $this->functionNameMap[$cell->getValue()] = $cell->getRow();
- }
- continue;
- }
- if ($cell->getValue() != '') {
- if (is_bool($cell->getValue())) {
- $this->log($cell->getRow() . ' -> ' . ($cell->getValue() ? 'TRUE' : 'FALSE'));
- $this->functionNameMap[($cell->getValue() ? 'TRUE' : 'FALSE')] = $cell->getRow();
- } else {
- $this->log($cell->getRow() . ' -> ' . $cell->getValue());
- $this->functionNameMap[$cell->getValue()] = $cell->getRow();
- }
- }
- }
- }
- }
- private function isFunctionCategoryEntry(Cell $cell): bool
- {
- $categoryCheckCell = self::ENGLISH_FUNCTION_CATEGORIES_COLUMN . $cell->getRow();
- if ($this->functionNameTranslations->getCell($categoryCheckCell)->getValue() != '') {
- return true;
- }
- return false;
- }
- private function log(string $message): void
- {
- if ($this->verbose === false) {
- return;
- }
- echo $message, self::EOL;
- }
- }
|