A Walking Heroic History
"Besides,” Harry said, “It seems pretty simple to me. You were a git, and I hated you. Now you’re not a git, and I love you. Easy as that.”
For @harryjamespotterweek 2023, Day 3 (Scars, Enemies to Lovers)
Rated T, 1.2k words. Read on ao3 here
“What about this one?” Draco’s fingers, tacky with sea salt, caught on Harry’s skin, just above his hip.
“Third year. The Whomping Willow got me, I think, or maybe it was when I fell by the lake with the Dementors after that.”
Draco bent to place a gentle kiss on the scar, then his fingers continued their exploration up Harry’s side.
“This one?” he asked, pressing a small kiss to it preemptively, smirking when Harry twitched away, huffing out a laugh.
“That tickles.”
Draco did it again, just to make him squirm.
“Fell out of a tree when I was eight. I bounced when I hit the ground, but a branch caught me first.”
One last, tickling kiss, and Draco moved on again.
Over Harry’s shoulder - “I genuinely have no clue, I just noticed it one day in fifth year,” - down Harry’s arm - “Wormtail, in the cemetery, fourth year,” - all the way to his hand.
“Umbridge and her evil quill in fifth year.”
Draco linked their fingers and lay back, pulling Harry’s hand up to his mouth for another kiss, gritty with the sand stuck to his skin.
“We all wondered about that, you know,” Draco said, idly tracing the letters. “In Slytherin. We all knew you had cuts on the back of your hands Blaise even set up a betting pool on it.”
“Who won?”
“Daphne Greengrass. She asked a Gryffindor boy who had seen you in the common room and he told her. To hear her tell it, she seduced it out of him, but I suspect he didn’t see any reason not to answer her when she asked.”
Harry gave another small laugh, sun-warm and content, and after a moment, Draco continued.
“I am sorry, about all of that. I don’t think I mentioned that when I said- before. But I am sorry for the Inquisitorial Squad, and what she did to you.”
Harry gave his hand a gentle squeeze. “You don’t have to keep apologizing. I know.” In an even softer voice, he added, “I still remember what you said that first time. Besides,” Harry said, continuing on at his normal volume, “It seems pretty simple to me. You were a git, and I hated you. Now you’re not a git, and I love you. Easy as that.”
Draco squeezed his hand back, and Harry kissed his fingertips.
“Second year,” said Draco, and Harry hummed a question in response. “On my ring finger, on the side, near where you kissed, there’s a scar from second year.”
Harry sought it out, found it between Draco’s second and third knuckles, pointing to the place where Harry suspected he would put a ring someday in the near future. It was still too soon to be proposing, but Harry kissed the shiny silver scar, and then kissed the bottom of Draco’s finger too, as a placeholder for now.
“What happened?” Harry asked, “Did the Basilisk get you too?”
Draco elbowed him hard in the ribs.
“No. You did, actually.”
“What? When did I hurt you in second year?” Harry was sure he would have remembered attacking Draco in second year, not least of all because Draco would have thrown such a fit that everyone in Hogwarts would have surely remembered it.
“During the Dueling Club,” Draco said, his smug smile evident even in his voice.
“I did not!” Harry protested, sitting up so fast he flung sand into Draco’s face.
Draco tossed his head to flick the errant sand away, then opened his eyes looking incredibly pleased with himself.
“You did. You sent me flying back, and I scraped my finger on the ground.”
Harry couldn’t see his own face, but he was sure it looked as unimpressed as he felt.
“That’s hardly anything! How on earth did it scar? Why didn’t you have someone heal you? It can’t have been that bad, or else someone would have noticed the blood.”
“Well, it wasn’t that bad at first, Potter,” Draco drawled, so horribly self-satisfied Harry almost choked on it. “But you see, I hated you then, because you had refused my offer of friendship, and everyone thought you were the Heir of Slytherin, and I just couldn’t let any of that go. So, I didn’t let it heal, and kept making it worse, because you were my sworn enemy, and I wanted the burden of being marked by your cruel villainy for the rest of my life.”
Harry blinked down at him for a second, then said, “You’re insane.”
“I was twelve, everyone’s like that when they’re twelve,” Draco responded placidly, so sure of himself that Harry wanted to contradict him, wanted to tell him no, not everyone is like that when they’re twelve. But then, he remembered that he, Ron, and Hermione had spent the first half of that year brewing Polyjuice Potion because they were convinced Draco was the Heir of Slytherin, and the sheer hypocrisy of saying that made him pause.
Finally, he just kissed Draco’s petty little scar and let their hands fall back to the beach.
“Whatever you say, Draco.”
A few more moments passed in silence, both of them listening to the crash of the waves before Draco spoke again.
“I like them, you know. Your scars.”
Harry had known this for a while; Draco’s hands often sought them out as though they were there to mark the places Harry was meant to be held, pieced back together under a loving and careful touch.
“I don’t like that you had to suffer to get them, of course,” Draco continued, thumb stroking over the back of Harry’s hand as if to read the words carved there through touch alone. “I truly am sorry about that, even about the hurts I didn’t cause. But I like history, I always have, and growing up I liked stories about heroes best of all. And you, you’re a walking heroic history, and I like seeing that. Of course, it also reminds me that you’re a reckless, self-sacrificing moron on occasion too, but I feel that’s just a reminder that you need to keep me around so at least one of us is looking out for you.”
And then, never one to want attention paid to him after being too nice, Draco put his head on Harry’s shoulder and indicated with every fibre of his being that their conversation was now over, and he was going to relax for the rest of the afternoon.
Harry intended to do the same, letting the sound of the waves, the steady rise and fall of Draco’s breath, and the rhythmic carding of his fingers through Draco’s hair soothe him. But, at the same time, he found he couldn’t help but turn over Draco’s words in his mind.
Harry had never really thought much about his body before - it had always done what he had needed it to do, and it hadn’t hindered him, parts/he had never had cause to contemplate himself in the way Draco clearly had. Harry supposed, if pressed, he would say that he liked how much he resembled his parents, the first people ever to love him, and the first people he lost, living on a bit through him. But hearing how Draco thought about him, what he liked about the scar on Harry that had just seemed like collateral damage in a much bigger fight, that made Harry re-evaluate his own blind neutrality.
He pulled Draco’s hand to his mouth to kiss his precious little scar again, and Draco, napping lightly beside him, moved his hand to cover the scar on Harry’s chest, and smiled in his sleep.
36 notes
·
View notes
Two Ways to Create Custom Translated Messaging for HTML Forms
New Post has been published on https://thedigitalinsider.com/two-ways-to-create-custom-translated-messaging-for-html-forms/
Two Ways to Create Custom Translated Messaging for HTML Forms
HTML forms come with built-in ways to validate form inputs and other controls against predefined rules such as making an input required, setting min and max constraints on range sliders, or establishing a pattern on an email input to check for proper formatting. Native HTML and browsers give us a lot of “free” features that don’t require fancy scripts to validate form submissions.
And if something doesn’t properly validate? We get “free” error messaging to display to the person using the form.
These are usually good enough to get the job done, but we may need to override these messages if we need more specific error content — especially if we need to handle translated content across browsers. Here’s how that works.
The Constraints API
The Constraints API is used to override the default HTML form validation messages and allows us to define our own error messages. Chris Ferdinandi even covered it here on CSS-Tricks in great detail.
In short, the Constraints API is designed to provide control over input elements. The API can be called at individual input elements or directly from the form element.
For example, let’s say this simple form input is what we’re working with:
<form id="myForm"> <label for="fullName">Full Name</label> <input type="text" id="fullName" name="fullName" placeholder="Enter your full name" required> <button id="btn" type="submit">Submit</button> </form>
We can set our own error message by grabbing the <input> element and calling the setCustomValidity() method on it before passing it a custom message:
const fullNameInput = document.getElementById("fullName"); fullNameInput.setCustomValidity("This is a custom error message");
When the submit button is clicked, the specified message will show up in place of the default one.
Translating custom form validation messages
One major use case for customizing error messages is to better handle internationalization. There are two main ways we can approach this. There are other ways to accomplish this, but what I’m covering here is what I believe to be the most straightforward of the bunch.
Method 1: Leverage the browser’s language setting
The first method is using the browser language setting. We can get the language setting from the browser and then check whether or not we support that language. If we support the language, then we can return the translated message. And if we do not support that specific language, we provide a fallback response.
Continuing with the HTML from before, we’ll create a translation object to hold your preferred languages (within the script tags). In this case, the object supports English, Swahili, and Arabic.
const translations = en: required: "Please fill this", email: "Please enter a valid email address", , sw: required: "Sehemu hii inahitajika", email: "Tafadhali ingiza anwani sahihi ya barua pepe", , ar: required: "هذه الخانة مطلوبه", email: "يرجى إدخال عنوان بريد إلكتروني صالح", ;
Next, we need to extract the object’s labels and match them against the browser’s language.
// the translations object const supportedLangs = Object.keys(translations); const getUserLang = () => // split to get the first part, browser is usually en-US const browserLang = navigator.language.split('-')[0]; return supportedLangs.includes(browserLang) ? browserLang :'en'; ; // translated error messages const errorMsgs = translations[getUserLang()];// form element const form = document.getElementById("myForm");// button elementconst btn = document.getElementById("btn");// name input const fullNameInput = document.getElementById("fullName");// wrapper for error messaging const errorSpan = document.getElementById("error-span"); // when the button is clicked… btn.addEventListener("click", function (event) // if the name input is not there… if (!fullNameInput.value) // …throw an error fullNameInput.setCustomValidity(errorMsgs.required); // set an .error class on the input for styling fullNameInput.classList.add("error"); );
Here the getUserLang() function does the comparison and returns the supported browser language or a fallback in English. Run the example and the custom error message should display when the button is clicked.
Method 2: Setting a preferred language in local storage
A second way to go about this is with user-defined language settings in localStorage. In other words, we ask the person to first select their preferred language from a <select> element containing selectable <option> tags. Once a selection is made, we save their preference to localStorage so we can reference it.
<label for="languageSelect">Choose Language:</label> <select id="languageSelect"> <option value="en">English</option> <option value="sw">Swahili</option> <option value="ar">Arabic</option> </select> <form id="myForm"> <label for="fullName">Full Name</label> <input type="text" id="fullName" name="fullName" placeholder="Enter your full name" required> <span id="error-span"></span> <button id="btn" type="submit">Submit</button> </form>
With the <select> in place, we can create a script that checks localStorage and uses the saved preference to return a translated custom validation message:
// the <select> element const languageSelect = document.getElementById("languageSelect"); // the <form> element const form = document.getElementById("myForm"); // the button element const btn = document.getElementById("btn"); // the name input const fullNameInput = document.getElementById("fullName"); const errorSpan = document.getElementById("error-span"); // translated custom messages const translations = en: required: "Please fill this", email: "Please enter a valid email address", , sw: required: "Sehemu hii inahitajika", email: "Tafadhali ingiza anwani sahihi ya barua pepe", , ar: required: "هذه الخانة مطلوبه", email: "يرجى إدخال عنوان بريد إلكتروني صالح", ; // the supported translations object const supportedLangs = Object.keys(translations); // get the language preferences from localStorage const getUserLang = () => const savedLang = localStorage.getItem("preferredLanguage"); if (savedLang) return savedLang; // provide a fallback message const browserLang = navigator.language.split('-')[0]; return supportedLangs.includes(browserLang) ? browserLang : 'en'; ; // set initial language languageSelect.value = getUserLang(); // update local storage when user selects a new language languageSelect.addEventListener("change", () => localStorage.setItem("preferredLanguage", languageSelect.value); ); // on button click btn.addEventListener("click", function (event) // take the translations const errorMsgs = translations[languageSelect.value]; // ...and if there is no value in the name input if (!fullNameInput.value) // ...trigger the translated custom validation message fullNameInput.setCustomValidity(errorMsgs.required); // set an .error class on the input for styling fullNameInput.classList.add("error"); );
The script sets the initial value to the currently selected option, saves that value to localStorage, and then retrieves it from localStorage as needed. Meanwhile, the script updates the selected option on every change event fired by the <select> element, all the while maintaining the original fallback to ensure a good user experience.
If we open up DevTools, we’ll see that the person’s preferred value is available in localStorage when a language preference is selected.
Wrapping up
And with that, we’re done! I hope this quick little tip helps out. I know I wish I had it a while back when I was figuring out how to use the Constraints API. It’s one of those things on the web you know is possible, but exactly how can be tough to find.
References
0 notes