···126126 }
127127 }
128128 })
129129+ doc.Find("[i18n-attrs]").Each(func(_ int, element *goquery.Selection) {
130130+ element.RemoveAttr("i18n-attrs")
131131+ // find all attributes that start with "i18n:"
132132+ for _, attribute := range element.Nodes[0].Attr {
133133+ if !strings.HasPrefix(attribute.Key, "i18n:") {
134134+ continue
135135+ }
136136+ if strings.HasPrefix(attribute.Key, "i18n:commas:") {
137137+ // Multi-valued attributes
138138+ translated := attribute.Val
139139+ if t.language != SourceLanguage {
140140+ translated = ""
141141+ for _, val := range strings.Split(attribute.Val, ",") {
142142+ translatedItem, err := t.GetTranslation(val, "")
143143+ if err != nil {
144144+ color.Yellow("[%s] Missing translation for %q", t.language, val)
145145+ t.missingMessages = append(t.missingMessages, po.Message{
146146+ MsgId: val,
147147+ MsgContext: "",
148148+ })
149149+ translatedItem = val
150150+ }
151151+ translated += "," + translatedItem
152152+ }
153153+ translated = strings.Trim(translated, ",")
154154+ }
155155+ element.RemoveAttr(attribute.Key)
156156+ element.SetAttr(strings.TrimPrefix(attribute.Key, "i18n:commas:"), translated)
157157+ } else {
158158+ // Translate the attribute
159159+ translated := attribute.Val
160160+ if t.language != SourceLanguage {
161161+ var err error
162162+ translated, err = t.GetTranslation(attribute.Val, "")
163163+ if err != nil {
164164+ color.Yellow("[%s] Missing translation for %q", t.language, attribute.Val)
165165+ t.missingMessages = append(t.missingMessages, po.Message{
166166+ MsgId: attribute.Val,
167167+ MsgContext: "",
168168+ })
169169+ translated = attribute.Val
170170+ }
171171+ }
172172+ element.RemoveAttr(attribute.Key)
173173+ element.SetAttr(strings.TrimPrefix(attribute.Key, "i18n:"), translated)
174174+ }
175175+ }
176176+ })
129177 htmlString, _ := doc.Html()
130178 htmlString = strings.ReplaceAll(htmlString, "<i18n>", "")
131179 htmlString = strings.ReplaceAll(htmlString, "</i18n>", "")
···139187 translationsFilepath := fmt.Sprintf("i18n/%s.po", languageCode)
140188 poFile, err := po.LoadFile(translationsFilepath)
141189 if err != nil {
142142- color.Yellow("[%s] Couldn't load translations: %s", languageCode, err)
143143- err = WriteEmptyPOFile(languageCode)
144144- if err != nil {
145145- return nil, fmt.Errorf("while writing empty PO file: %w", err)
190190+ if os.IsNotExist(err) {
191191+ color.Yellow("[%s] Missing translation file for %s", languageCode, err)
192192+ err = WriteEmptyPOFile(languageCode)
193193+ if err != nil {
194194+ return nil, fmt.Errorf("while writing empty PO file: %w", err)
195195+ }
196196+ return LoadTranslations(languages)
197197+ } else {
198198+ return nil, fmt.Errorf("while loading translations for %s: %w", languageCode, err)
146199 }
147147-148148- return LoadTranslations(languages)
149200 } else {
150201 translations[languageCode] = &Translations{
151202 poFile: *poFile,
···262313// GetTranslation returns the msgstr corresponding to msgid and msgctxt from the .po file
263314// If not found, it returns an error
264315func (t Translations) GetTranslation(msgid string, msgctxt string) (string, error) {
316316+ if msgid == "" {
317317+ return "", nil
318318+ }
265319 t.seenMessages.Add(msgid + msgctxt)
266320 for _, message := range t.poFile.Messages {
267321 if message.MsgId == msgid && message.MsgStr != "" && message.MsgContext == msgctxt {
+2-2
i18n/fr-unused-messages.yaml
···11-# Generated at 2023-12-23 18:28:11.936834364 +0100 CET m=+0.310897677
11+# Generated at 2023-12-24 15:16:17.424568197 +0100 CET m=+0.334085318
22- "%s’s logo"
33- "%v-day streak on Duolingo, %v league"
44- "1104<sup>th</sup>"
···4646- "This page does not exist (anymore)"
4747- "Unknown error"
4848- "Unknown year"
4949+- "Works"
4950- "about"
5051- "about me"
5152- "all"
···102103- "what"
103104- "work in progress"
104105- "work time tracked by <a href=\"https://wakatime.com\">WakaTime</a>"
105105-- "works"
106106- "works by tag"
107107- "works made with"
108108- "works made with %s"
+27-24
i18n/fr.po
···1212"Content-Transfer-Encoding: 8bit\n"
1313"X-Generator: Poedit 3.4.1\n"
14141515+msgid "Search"
1616+msgstr "Rechercher"
1717+1518msgid "%s’s logo"
1619msgstr "Logo de %s"
1720···77807881msgid "A high-quality typesetting & document preparation system"
7982msgstr "Un système de composition et de préparation des documents de haute qualité"
8383+8484+msgid "A human friendly data serialization standard for all programming languages"
8585+msgstr "Une norme de sérialisation des données pour tous les langages de programmation"
8686+8787+msgid "A language empowering everyone to build reliable and efficient software"
8888+msgstr "Un langage permettant à chacun de construire des logiciels fiables et efficaces"
8989+9090+msgid "A language for generating UML diagrams from textual descriptions"
9191+msgstr "Un langage permettant de générer des diagrammes UML à partir de descriptions textuelles"
80928193msgid "A simple cross-platform library to create graphical user interfaces in [Go](/using/go) that work on Android, iOS, Linux, MacOS and Windows."
8294msgstr "Une bibliothèque multiplateforme simple pour créer des interfaces graphiques en [Go](/using/go) qui fonctionnent sur Android, iOS, Linux, MacOS et Windows."
···90102msgid "Get my resume"
91103msgstr "Voir mon CV"
921049393-msgid "A human friendly data serialization standard for all programming languages"
9494-msgstr "Une norme de sérialisation des données pour tous les langages de programmation"
9595-9696-msgid "A language empowering everyone to build reliable and efficient software"
9797-msgstr "Un langage permettant à chacun de construire des logiciels fiables et efficaces"
9898-9999-msgid "A language for generating UML diagrams from textual descriptions"
100100-msgstr "Un langage permettant de générer des diagrammes UML à partir de descriptions textuelles"
101101-102105msgid "A language which compiles to JavaScript that adds many features to assist in functional style programming. LiveScript is an indirect descendant of CoffeeScript, with which it has much compatibility."
103106msgstr "Un langage qui se compile en JavaScript et qui ajoute de nombreuses fonctionnalités pour aider à la programmation de style fonctionnel. LiveScript est un descendant indirect de CoffeeScript, avec lequel il a une grande compatibilité."
104107···141144msgid "A programming language that compiles to JavaScript. It adds syntactic sugar inspired by Ruby, Python and Haskell in an effort to enhance JavaScript's brevity and readability. Specific additional features include list comprehension and destructuring assignment"
142145msgstr "Un langage de programmation qui se compile en JavaScript. Il ajoute du sucre syntactique inspiré de Ruby, Python et Haskell dans le but d'améliorer la brièveté et la lisibilité de JavaScript. Les caractéristiques supplémentaires spécifiques comprennent la définition de listes en compréhension et l'affectation par déstructuration"
143146147147+msgid "A programming language that compiles to JavaScript. It adds syntactic sugar inspired by Ruby, Python and Haskell in an effort to enhance JavaScript’s brevity and readability. Specific additional features include list comprehension and destructuring assignment"
148148+msgstr "Un langage de programmation qui se compile en JavaScript. Il ajoute du sucre syntaxique inspiré de Ruby, Python et Haskell dans le but d'améliorer la brièveté et la lisibilité de JavaScript. Les fonctionnalités supplémentaires spécifiques incluent la compréhension de liste et l'affectation par décomposition"
149149+150150+msgid "A programming language that lets you work quickly and integrate systems more effectively"
151151+msgstr "Un langage de programmation permettant de travailler rapidement et d'intégrer des systèmes plus efficacement"
152152+153153+msgid "A progressive Node.js framework for building efficient, reliable and scalable server-side applications"
154154+msgstr "Un framework Node.js progressif pour construire des applications côté serveur efficaces, fiables et évolutives"
155155+156156+msgid "A radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when the app is built"
157157+msgstr "Une approche radicalement nouvelle de la construction d'interfaces utilisateurs. Alors que les frameworks traditionnels comme React et Vue font l'essentiel de leur travail dans le navigateur, Svelte transforme ce travail en une étape de compilation qui se produit lors de la création de l'application"
158158+144159msgid "Hi! I'm Ewen Le Bihan."
145160msgstr "Hey! Je suis Ewen Le Bihan."
146161···167182168183msgid "web extension"
169184msgstr "extension pour navigateur"
170170-171171-msgid "A programming language that compiles to JavaScript. It adds syntactic sugar inspired by Ruby, Python and Haskell in an effort to enhance JavaScript’s brevity and readability. Specific additional features include list comprehension and destructuring assignment"
172172-msgstr "Un langage de programmation qui se compile en JavaScript. Il ajoute du sucre syntaxique inspiré de Ruby, Python et Haskell dans le but d'améliorer la brièveté et la lisibilité de JavaScript. Les fonctionnalités supplémentaires spécifiques incluent la compréhension de liste et l'affectation par décomposition"
173173-174174-msgid "A programming language that lets you work quickly and integrate systems more effectively"
175175-msgstr "Un langage de programmation permettant de travailler rapidement et d'intégrer des systèmes plus efficacement"
176176-177177-msgid "A progressive Node.js framework for building efficient, reliable and scalable server-side applications"
178178-msgstr "Un framework Node.js progressif pour construire des applications côté serveur efficaces, fiables et évolutives"
179179-180180-msgid "A radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when the app is built"
181181-msgstr "Une approche radicalement nouvelle de la construction d'interfaces utilisateurs. Alors que les frameworks traditionnels comme React et Vue font l'essentiel de leur travail dans le navigateur, Svelte transforme ce travail en une étape de compilation qui se produit lors de la création de l'application"
182185183186msgid "A radical new approach to building user interfaces. Whereas traditional frameworks like React and Vue do the bulk of their work in the browser, Svelte shifts that work into a compile step that happens when you build your app."
184187msgstr "Une approche radicale pour la création d'interfaces utilisateur. Alors que les frameworks traditionnels tels que React et Vue effectuent la majeure partie de leur travail dans le navigateur, Svelte déplace ce travail dans une étape de compilation qui se produit lors de la création de l'application."
···362365msgid "Redirecting you to my github incubator..."
363366msgstr "Redirection vers mon incubateur github..."
364367365365-msgid "Set of glyphs (letters, punctuation marks and more) that define how text looks."
366366-msgstr "Ensemble de glyphes (lettres, signes de ponctuation et plus encore) qui définissent l'apparence du texte."
367367-368368msgid "School projects and school-related projects"
369369msgstr "Projets scolaires et projets liés à l'école"
370370371371msgid "Server error. I f*cked up somewhere."
372372msgstr "Erreur serveur. J'ai foiré quelque part."
373373+374374+msgid "Set of glyphs (letters, punctuation marks and more) that define how text looks."
375375+msgstr "Ensemble de glyphes (lettres, signes de ponctuation et plus encore) qui définissent l'apparence du texte."
373376374377msgid "Short introductory video sequences typically played at the beginning of every video"
375378msgstr "Séquences vidéo introducientrières courtes qui sont typiquement jouées au début de chaque vidéo"