A career entry says the same thing in more than one language #131
Labels
No labels
accessibility
authentication
breaking change
bug
documentation
enhancement
interface
internationalisation
observability
security
tier
1
tier
2
tier
3
tier/4
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
#133 A document is a kind, and a kind is a plugin
Postulo/postulo
Reference
Postulo/postulo#131
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Observation
What exists
At the document level this is already true, and better than it looks. Both
CVandCoverLettercarry alanguagefield — "Which language this variant is written in. Leaveblank to follow your profile." — and
rendering.document_language()resolves it bestanswer first: what the document says, then what its owner reads Postulo in, then the
instance default, with British English as a last resort rather than an assumption.
document_direction()then reads the layout direction from the document's language andnot the reader's, with the reason written out:
The image carries
fonts-noto-coreand a test holds the fonts to the languages offered(#70), so an Amharic or Georgian document renders glyphs rather than boxes. So a French CV
and an English CV can sit side by side today, each declaring itself correctly.
One level down, they cannot say anything different. The career record holds one text per
field per entry:
Experiencerole,organisation,location,summary,highlightsEducationinstitution,qualification,field_of_study,grade,highlightsProjectname,role,summary,highlightsCertificationname,issuerSkillGroup,SkillnameA CV declaring
fr-frrenders exactly the same English job titles and summaries as the onedeclaring
en-gb. The only per-variant escape isCVItem.override_highlights, whichreplaces the highlights on one variant and nothing else — one field out of the table above.
So today the honest way to keep a CV in two languages is two careers: a second set of
entries, typed again, drifting apart from the first the moment a date changes.
What this asks for
A career entry that can say the same thing in more than one language, so that a second
language is a translation rather than a second record.
Worth being careful about
Which of the fields above should even be translated. An organisation's name usually
should not — Universidade de Lisboa stays that in an English CV — and a qualification
sometimes must not, because the awarding body's name is the credential. A blanket
per-language copy of every field would invite somebody to translate the one thing that has
to stay verbatim. This wants a decision per field, not a mechanism applied uniformly.
Three shapes, and they are not equally good. Per-entry translation rows keyed by language
(clean, and a join everywhere); a JSON map of language to overrides on the entry (no
migration per field, no constraints either); or per-variant overrides on
CVItem, extendingwhat
override_highlightsalready does (smallest change, but the translation belongs to theCV rather than to the career, so a second French CV retypes it).
Falling back has to be visible. A French CV with an untranslated entry should render the
original rather than a blank — and the person should be able to see which entries fell
back, or they will discover it in the PDF an employer already has.
The export and the importer. Whatever holds the translations travels in the archive and
comes back;
core/export.pywalks the career models field by field, and the Europass readerfills them.
Europass is bilingual in practice. The importer reads a file that may itself carry more
than one language, and today collapses it to one. Worth knowing before designing the
storage, rather than after.
Letters are different from CVs here. A letter is prose the person wrote, not a selection
from a record; two languages means two letters, which is already possible and probably
correct. This issue is about the career record behind a CV, a portfolio and a report — the
kinds that assemble rather than the ones that are written.
Every language on a document is a language the fonts must draw. That already holds for
the interface; it now applies to a person's own words in a PDF, which is a different code
path (WeasyPrint, or Chromium) with its own font resolution.
Done in
28551c13.The shape chosen, and why not the other two
Of the three the issue listed, this is per-entry translation rows keyed by language — but a row per field, not a row per entry with a column per field.
CVItemwere rejected for the reason the issue gave: the translation would belong to the CV rather than to the career, so a second French CV would retype it.So: a generic link, exactly as
CVItemandPostalAddressalready use, with the field name checked againsttranslating.TRANSLATABLE.Which fields — the decision, not a mechanism
You were right that a blanket per-language copy of every field would invite somebody to translate the one thing that has to stay verbatim, and that offering the box is the harm. So the boxes that would have caused it are not there:
Experiencerole,location,summary,highlightsorganisation— Universidade de Lisboa stays that on an English CVEducationqualification,field_of_study,location,grade,highlightsinstitution— same reasonProjectname,role,summary,highlightsSkillGroup,Skill,LanguageSkillnameLinktitle,descriptionurl,kindCertificationCertificationtranslating nothing at all is a statement rather than a gap, and the screen says so in words rather than showing an empty form.What is offered is either the person's own words or something that genuinely differs between languages: a job title, a city (Lisbon, Lisboa), a qualification, a grade on a scale that does not exist elsewhere.
Falling back, made visible
An entry with nothing in the CV's language prints its original — a blank line where a job used to be is worse than a line in the wrong language. The CV's own page then lists which entries did that and in which fields, each linking to its translation screen, above the export button. Same rule #132 settled for themes, one issue earlier, for the same reason.
That is what the one new profile field earns its place with. Without "which language is your career record written in", a CV declaring that same language would report every entry as untranslated, and a warning that always fires is read once and then never again. Blank means "the same as the interface", which is a guess rather than a claim — and the reason it is not simply read from the interface language is that the two are genuinely different questions: somebody reading Postulo in English may have typed their career in Portuguese.
What the templates had to know: nothing
build_sectionshands each theme anEntryexposing the two names a template already reads —entry.itemandentry.highlight_lines— so every theme renders a translated CV without knowing translations exist. That matters most for the themes Postulo has never seen: a plugin's template written againstentry.item.rolegets the French job title and could not have been asked to do anything else.One entry is printed through another and needed handling: a
Skillis never on a CV in its own right, only through its group'sskill_names. Offering to translate a skill's name and then never printing the translation would have been a worse promise than not offering it.Cost
A generic link has no join to
select_related, so the same batch lookup #130 introduced answers for it: one query for a whole CV's translations, not one per entry. The career overview does the same for its "Also in French, German" line.Europass
Left where it was, deliberately, and the module says so. The reader collapses each file to one language; reading two files as one career is its own piece of work. What this had to get right first was being able to hold the second file's text when it arrives — which was your point about knowing before designing the storage rather than after — and it can: the rows are keyed by (entry, language, field) and care nothing about where the text came from.
Also
pt-brtakespt-ptwhere nopt-brexists. A Brazilian reader given European Portuguese has read the entry; given English, they have not.tests/test_career_languages.py, 27 tests. Suite 4138 passed, 29 skipped; browser suite 54 passed, including axe-core over the new screen in both themes.One thing found on the way, fixed separately in
144978f2: #130 tookrelated_name="renders"with the two columns it replaced, and both detail pages ask for exactly that name — so opening a CV or a letter raised anAttributeError. The tests written for #130 checked what the new link stores and what happens when each end is deleted, and never opened the page that reads it back. The reverse is a query rather than aGenericRelation, because a relation would bring a cascade with it and deleting a CV must leave the PDF an employer received where it is.