Package: ul-translation-sdk
TranslationСервис переводовДля понимания это управление умной экселькой, в которой первая колонка это ключ перевода, а вторая и последующие колонки - перевод на разных языках (каждая колонка - это новый язык)Make New Enc Keysulapiutlsenc_keys--algorithmRS256--follower-servicestranslation-web--service-nametranslation-auth--jwt-permissions-modulesrc.conf.permissions--jwt-environmentlocal--jwt-user-id6ff8eaba-b5b4-49b2-9a83-f48fcdf6d361Servicestranslation__balancer = nginxtranslation__public_api = flask+sqlalchemytranslation__internal_api = flask+sqlalchemytranslation__auth_api = COMMON SERVICEtranslation__management_view = flask+jingja2translation__db = pg14translation__db_ui = pgwebСтруктура хранимых данныхlang:id:uuid, pkuser_created:uuid, fk(api_user)user_modified:uuid, fk(api_user)date_created:date-time, utcdate_modified:date-time, utcis_alive:boolname:str(255), uniq# human readable text in ANY LANGUAGEabbr:str(10), uniq, ASCII symbols only, RESTRICT WHITE SPACES# exaples - en, ru, en_EN, en_US, ...key:id:uuid, pkuser_created:uuid, fk(api_user)user_modified:uuid, fk(api_user)date_created:date-time, utcdate_modified:date-time, utcis_alive:boolname:str(255), uniq, ASCII symbols only, RESTRICT WHITE SPACES !!!!# examples - "account.something.0.else",   "user_profile.full_name", "name"translation:# не может стать удаленным или помечен быть как удаленid:uuid, pkuser_created:uuid, fk(api_user)user_modified:uuid, fk(api_user)date_created:date-time, utcdate_modified:date-time, utclang_id:fk(lang)key_id:fk(key)content:text#  ЛЮБАЯ СТРОКА. БЕЗ ВАЛИДАЦИИ. ПУСТАЯ СТРОКА ВАЛИДНАtranslation_cache:# material-view, trigger(translation, key, lang). ТОЛЬКО активные записиtranslation_id:uuid, fk(translation)lang_abbr:str(10)key_name:str(255)translation_content:text# constaint: uniq_together(lang_id, key_id, content)PUBLIC API serviceGET/lang/en_EN/translation-cacheгдеen_EN- это существующая абривиатура языканет авторизации. ЛЮБОЙ может получить ответКэш запроса на уровнеnginx= 1 часСтроится ответ по таблицеtranslation-cacheключи сортируются согласно alpha-numeric{"key.name":"translation_content","field.0.some":"translation_content 2",/*другие ключи этого языка и переводы к ним*/}если такого языка не найдено вtranslation_cacheто возвращается пустой обьект со статусом 404GET/lang/en_EN/translation-cache-compiledтоже самое что и GET/lang/en_EN/translation-cacheНО ключи разворачиваются согласно точкам в структуры обьектовесли точка вначале или в конце - игнорируютсяНапрмерkey.name- это вложенные обьекты. в первом есть атрибутkeyи его значение равен обьекту у которого есть ключname. пустая строка = валидное проперти обьекта{"key":{"name":"translation_content",},"field":{"0":{"some":"translation_content 2"}},/*другие ключи этого языка и переводы к ним*/}Решением построения дерева предлагается как утилитарная функцияdefset_obj_attr_by_path(mut_obj:Dict[str,Any],path_key:str,value:Any)->NDict[str,Any]:obj=mut_objsegments=path_key.strip(".").split(".")fori,segmentinenumerate(segments):ifi==(len(segments)-1):obj[segment]=valueelse:ifsegmentnotinobj:obj[segment]=dict()obj=obj[segment]returnmut_objINTERNAL API serviceLanguages APIGET/langsПолучение списка всех (даже неактивных) языков
(при создании нового, создаются записи для всех переводовtranslationпо всем существующим ключам с пустым контентом)/* Response example */[{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"English","abbr":"en_EN",},...]GET/langs/:idПолучение списка конкретного языка/* Response example */{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"English","abbr":"en_EN",}POST/langs/Созданиен языка/* Request example */{"name":"Russian","abbr":"ru_RU",}PUT/langs/:idИзменение конкретного языка/* Request example */{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"Russian","abbr":"ru_RU",}DELETE/langs/:idУдаление конкретного языкаKeys APIGET/keysПолучение списка всех (даже неактивных) ключей/* Response example */[{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"field.3.some",},...]GET/keys/:idПолучение списка конкретного ключа/* Response example */{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"field.3.some",}POST/keys/Созданиен ключа/* Request example */{"name":"field.3.some",}PUT/keys/:idИзменение конкретного ключа/* Request example */{"id":"...","user_created":"...","user_modified":"...","date_created":"...","date_modified":"...","is_alive":"...","name":"field.3.some",}DELETE/keys/:idУдаление конкретного языкаTranslation APIGET/translationsПолучение списка всех переводов/* Response example */[{"translation_id":"fk(translation).id","lang_abbr":"en_EN","key_name":"field.3.some","translation_content":"",},...]GET/translations/:idПолучение списка конкретного переводов/* Response example */{"translation_id":"fk(translation).id","lang_abbr":"en_EN","key_name":"fields.3.some","translation_content":"some text",}POST/translationsСозданиен ключа/* Request example */{"translation_id":"fk(translation).id","content":"some text",}PUT/translationsИзменение конкретного ключа/* Request example */[{"translation_id":"fk(translation).id","content":"some text",}]View serviceРаботает через логин в котором вставляется токен авторизации в поле при старте приложенияТокен генерируется в Auth Apipages:LoginLangKeysTranslationImport *Export *Login PageОдно поле - токен, который потом записывается в куку, если токен валиденLang Pageэто таблица со всеми языками (даже с неактивными)можно редактировать языки, добавлять, удалять - через модалкумодалка - поля, кнопка сохранить, кнопка отменитьKeys Pageэто таблица со всеми ключами (даже с неактивными)можно редактировать ключи, добавлять, удалять - через модалкумодалка - поля, кнопка сохранить, кнопка отменитьTranslation Pageтаблица строится поtranslation_cacheиkeyВыводятся Абсолютно все активные записиколонки:ПЕРВАЯ КОЛОНКА = key_name  всех активных ключейостальные колонки это все доступные АКТИВНЫЕ языки и переводы к нимЯчейки в которых нет текста должны подстветиться оранжевым (или другим ярким) цветомстроки отсортированы по имени ключаНажимая на строку (или только на ключ строки) открывается модалка с изменениями сразу всех возможных переводов для данного ключа. ключ менять нельзя. после применения страница перезагружаетсямодалка - поля, кнопка сохранить, кнопка отменитьExport Page *Кнопка с генерацией файла на скачкуФормат файла - JSONЭкспортируются ТОЛЬКО активные записи !{"langs":[{/*... все поля языков*/},/*...*/],"key":[{/*... все поля ключей*/},/*...*/],"translation":[{/*... все поля переводов*/,/*...*/}],}Import Page *На странице есть кнопка с загрузкой файлаФормат файла точно соответсвует формату файла экспорта.Любое несоотвествие, лишние поля итп - ошибка !Если такой айди существует - контент заменяетсяПрименяется одной транзакцией