<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Noda</title>
    <description>The latest articles on DEV Community by Noda (@noda).</description>
    <link>https://dev.to/noda</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1169419%2Fbcb2ef24-d204-4efc-88c6-8b8a804cb15c.png</url>
      <title>DEV Community: Noda</title>
      <link>https://dev.to/noda</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/noda"/>
    <language>en</language>
    <item>
      <title>Why Security Testing is a Must-Have for Fintech Success</title>
      <dc:creator>Noda</dc:creator>
      <pubDate>Tue, 17 Dec 2024 10:10:40 +0000</pubDate>
      <link>https://dev.to/noda/why-security-testing-is-a-must-have-for-fintech-success-2lk0</link>
      <guid>https://dev.to/noda/why-security-testing-is-a-must-have-for-fintech-success-2lk0</guid>
      <description>&lt;p&gt;Written by Alena Khaitsina, Head of Manual QA at &lt;a href="https://noda.live/" rel="noopener noreferrer"&gt;Noda&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;The fintech sector is growing at an unprecedented pace. With more people relying on digital solutions for banking, investing, and payments, ensuring the security of these systems has become crucial. Unfortunately, as technology advances, so do the tools and techniques used by cybercriminals.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Rising Threat Landscape
&lt;/h2&gt;

&lt;h3&gt;
  
  
  A Growing Target for Cybercrime
&lt;/h3&gt;

&lt;p&gt;Cyberattacks have more than doubled since the pandemic and continue to grow in sophistication and impact. Not only is the number of cyberattacks growing, but incidents are becoming more sophisticated and dangerous.&lt;/p&gt;

&lt;p&gt;According to the Global Financial Stability Report, the risk of extreme losses from cyber incidents is increasing. The size of these extreme losses has more than quadrupled since 2017 to $2.5 billion. And indirect losses like repetitional damage or security upgrades are substantially higher.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngwkhb8msbxrep8e3xmn.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fngwkhb8msbxrep8e3xmn.jpg" alt="Image description" width="800" height="702"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Third-party exposure
&lt;/h3&gt;

&lt;p&gt;Cybercriminals can get around security systems by hacking less-protected networks belonging to third parties that have privileged access to the hacker’s primary target. &lt;/p&gt;

&lt;p&gt;For example: A third-party vendor is used to manage your customers' passwords. The third-party shifted to a hybrid work model over the past few years. During an ongoing due diligence review, you discover that their information security policy has no mention of virtual private networks (VPNs) or multi-factor authentication (MFA) for remote access. As a result, your organization is exposed to information security risks and potential data breaches that can affect your customers. &lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration mistakes
&lt;/h3&gt;

&lt;p&gt;A configuration issue can be as simple as using weak passwords or a more complex problem, such as improperly set up firewalls. &lt;br&gt;
Here are some of the most common configuration issues that lead to cyberattacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Failure to change device default configuration&lt;/li&gt;
&lt;li&gt;Network segmentation&lt;/li&gt;
&lt;li&gt;Not updating/patching computer software&lt;/li&gt;
&lt;li&gt;Using Weak Passwords&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why Security Testing is Critical
&lt;/h2&gt;

&lt;p&gt;Fintech products often handle highly sensitive information, including personal identification details, bank account numbers, and credit card information.&lt;/p&gt;

&lt;p&gt;Security testing isn’t optional — it’s essential. It protects sensitive financial data, safeguards user trust, and ensures regulatory compliance. &lt;/p&gt;

&lt;p&gt;What should be done? There are some ideas on what be implemented in the software development process according to Secure Software Development Lifecycle (SSDLC): &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Vulnerability Scanning: Regularly scan your application and its dependencies for vulnerabilities using automated tools.&lt;/li&gt;
&lt;li&gt;Penetration Testing: Regularly perform penetration testing (ethical hacking) to identify vulnerabilities before malicious actors do.&lt;/li&gt;
&lt;li&gt;API Security Testing: Test your APIs for common vulnerabilities like injection attacks, authentication flaws, and data exposure.&lt;/li&gt;
&lt;li&gt;Security Code Reviews: Conduct regular security-focused code reviews to identify potential vulnerabilities early.&lt;/li&gt;
&lt;li&gt;DevSecOps: Adopt DevSecOps principles to integrate security into your DevOps pipeline. This involves automating security tests, monitoring, and patching during the CI/CD process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far2jjtu590feym2428e4.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Far2jjtu590feym2428e4.jpg" alt="Image description" width="800" height="201"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Benefits of Security Testing
&lt;/h2&gt;

&lt;p&gt;Building Customer Trust&lt;/p&gt;

&lt;p&gt;Trust is a cornerstone of the financial services industry. Customers expect their financial data to be secure and are increasingly aware of the potential risks associated with online transactions. By implementing rigorous security testing protocols, fintech companies can demonstrate their commitment to protecting customer data. &lt;/p&gt;

&lt;p&gt;Regulatory Compliance&lt;/p&gt;

&lt;p&gt;Fintech companies operate in a heavily regulated environment. Non-compliance with security regulations can result in hefty fines and sanctions. Regular security testing helps ensure that products meet regulatory requirements, thereby avoiding legal issues and maintaining operational continuity. Staying ahead of compliance demands also positions companies favorably in the eyes of regulators and investors.&lt;/p&gt;

&lt;p&gt;Mitigating Risks&lt;/p&gt;

&lt;p&gt;Security testing is an essential risk management strategy. It enables fintech companies to identify potential vulnerabilities before they can be exploited. By employing various testing methods, such as penetration testing, vulnerability assessments, and code reviews, organizations can proactively address weaknesses in their systems. This approach not only reduces the likelihood of incidents but also minimises the impact should a breach occur.&lt;/p&gt;

&lt;p&gt;Enhancing Product Reliability&lt;/p&gt;

&lt;p&gt;Security testing contributes to the overall reliability of fintech products. A product that is secure is inherently more robust, leading to fewer downtimes and disruptions. This reliability is crucial for maintaining service levels and ensuring that customers can access their financial resources without interruption, thereby enhancing user experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Continuous Improvement: The Key to Staying Secure
&lt;/h2&gt;

&lt;p&gt;Security testing should not be a one-time event, but an ongoing process integrated into the software development lifecycle. By continuously testing and improving security measures, fintech companies can adapt to new challenges, ensuring their products remain secure in the face of evolving threats.&lt;/p&gt;

&lt;p&gt;Also, security testing is not just an added layer of protection for fintech products; it is a fundamental requirement for success in the industry. By prioritizing security testing, fintech companies can protect sensitive data, build customer trust, ensure regulatory compliance, mitigate risks, enhance product reliability, and foster continuous improvement. As the digital finance landscape continues to grow, the importance of security testing will only increase, making it an indispensable element of any fintech strategy&lt;br&gt;
 &lt;/p&gt;

</description>
      <category>security</category>
      <category>testing</category>
      <category>discuss</category>
    </item>
    <item>
      <title>How involve design team in testing for better user experience</title>
      <dc:creator>Noda</dc:creator>
      <pubDate>Mon, 29 Jan 2024 08:48:11 +0000</pubDate>
      <link>https://dev.to/noda/how-involve-design-team-in-testing-for-better-user-experience-1l33</link>
      <guid>https://dev.to/noda/how-involve-design-team-in-testing-for-better-user-experience-1l33</guid>
      <description>&lt;p&gt;&lt;strong&gt;Written by Elena Khaitsina, Lead QA Engineer at &lt;a href="https://noda.live/"&gt;Noda&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Usually, the common practice in Agile teams is that every department has well-known roles and responsibilities. &lt;/p&gt;

&lt;p&gt;For example, for the development team to work on creating code and unit tests. The business analysis team focuses on defining features that users will love, and simultaneously the design team explores the best ways to bring ideas to life through prototypes or design templates. The QA team plays a crucial role in validating the product. &lt;/p&gt;

&lt;p&gt;However, not everything goes smoothly in the Agile process.  &lt;/p&gt;

&lt;p&gt;From my experience, the primary bottleneck often arises when conceptual ideas confront the reality of implementation. For instance, designing a feature in a tool like Figma may differ significantly from how it's eventually implemented. &lt;/p&gt;

&lt;p&gt;Sometimes the differences were significant.  &lt;/p&gt;

&lt;p&gt;Besides checking the correct operation of created applications the guys from the QA department also verify the app views by checking the general appearance and the correctness of styles and content.  &lt;/p&gt;

&lt;p&gt;You’re almost ready to launch, but then you discover that you’ve focused on all the wrong things from the beginning: on the design phase. &lt;/p&gt;

&lt;p&gt;In light of these challenges, a compelling idea emerges: "How can we avoid this situation?" &lt;/p&gt;

&lt;p&gt;To address this, a potential solution is introduced – the use of Acceptance Testing by the Design team. This approach suggests involving the design team in acceptance testing to ensure that the final product not only meets functional requirements but also aligns seamlessly with the envisioned design. &lt;/p&gt;

&lt;h2&gt;
  
  
  Why is it so important?
&lt;/h2&gt;

&lt;p&gt;We know you’re probably wondering “Why bother?” &lt;/p&gt;

&lt;p&gt;The first and main reason is to find deficiencies between the design and implementation.  &lt;/p&gt;

&lt;p&gt;This includes not only functional discrepancies but also ensuring that the visual aspects align with the initial design.  &lt;/p&gt;

&lt;p&gt;Besides this, it helps a lot at the stage when the design doesn’t contain all the elements described in the requirements, e.g., missing buttons. &lt;/p&gt;

&lt;p&gt;Just for notice! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;"design testing is NOT the same as testing responsive design."&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;While responsive design testing focuses on adaptability, design testing involves a more comprehensive evaluation of the visual and interactive elements.  &lt;/p&gt;

&lt;p&gt;The second reason is to review if all design solutions work in real life. It's not just about functionality but about how users interact with the design elements in practical scenarios. This step ensures that the design not only looks good on paper but also functions seamlessly in the hands of the end-users. &lt;/p&gt;

&lt;p&gt;Of course, the prototype can help with this in the early phase but it’s not always time or needs to draw prototypes for small features or changes. &lt;/p&gt;

&lt;p&gt;The third reason is to get to know the application inside and out. It helps to be up to date with the functionality of the product. Also, the future design and implementation will be designed within the current features, ensuring a seamless and consistent user experience across updates and iterations. This comprehensive understanding aids not only in current testing but also in making informed decisions for future design enhancements and feature implementations. &lt;/p&gt;

&lt;h2&gt;
  
  
  Design testing in practice
&lt;/h2&gt;

&lt;p&gt;The process of product development has remained almost unchanged. &lt;/p&gt;

&lt;p&gt;The only additional step has been added and now the process becomes like this: when the testing phase is completed on test environments, a separate Acceptance Testing (AT) task is created. This task is assigned to the person responsible for the design of functionality. &lt;/p&gt;

&lt;p&gt;There’s one very important thing to remember! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;Design activities are an integral part of the User Story and are included in the Definition of Ready. This means that the story/features can’t be moved further along the flow. Therefore, if a design has bugs, then such a User Story cannot enter the development stage.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Next, the ball goes to the design team's side. &lt;/p&gt;

&lt;p&gt;The design team conducts a thorough review and provides feedback to the entire team. &lt;/p&gt;

&lt;p&gt;If needed, some changes in the current implementation are done. &lt;/p&gt;

&lt;p&gt;After all corrections, one more round of AT is initiated. &lt;/p&gt;

&lt;p&gt;If everything is OK – the AT is closed. &lt;/p&gt;

&lt;p&gt;Finally, the product is ready for the real user! &lt;/p&gt;

&lt;p&gt;Notice! &lt;/p&gt;

&lt;p&gt;&lt;em&gt;If the designs require corrections, you should do it as soon as possible and “freeze” the final version. Then, update the documentation/requirements. This will ensure development is conducted on the set-in-stone version.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fit79x7mcatslqxxx0z7d.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/cdn-cgi/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fit79x7mcatslqxxx0z7d.jpg" alt="Image description" width="800" height="718"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Benefit from design testing
&lt;/h2&gt;

&lt;p&gt;The benefits of design acceptance testing are vast. It’s not very time-consuming and it certainly adds value to the software development quality process. &lt;/p&gt;

&lt;p&gt;There are some points: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate new ideas you may not have thought of before while making prototypes and/or design templates. &lt;/li&gt;
&lt;li&gt;Feel confident in your product design decisions. &lt;/li&gt;
&lt;li&gt;Detect errors in the test environment before the customers will see them, which means much lower costs of improving them. &lt;/li&gt;
&lt;li&gt;Pay more attention to UX design. By clicking through the app you can check how easy it will be for real users to orientate not only to small new features but to the whole product. &lt;/li&gt;
&lt;li&gt;Check the differences/consistencies in the general design decisions relating to content, fonts, and colors. &lt;/li&gt;
&lt;li&gt;Testing provides necessary evidence of intuition and helps designers to alter products and services where required. &lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Everybody knows that the quality of a product is the responsibility of the whole team – not only the Quality Assurance Department. This rule also works in the &lt;a href="https://noda.live/"&gt;Noda&lt;/a&gt; team &lt;/p&gt;

&lt;p&gt;Moreover, Acceptance Testing (AT) by the Design team is not a replacement for User Acceptance (UA) testing by the QA team. Both play crucial roles in ensuring a robust and user-friendly final product. &lt;/p&gt;

&lt;p&gt;Both are crucial in ensuring a robust and user-friendly final product. &lt;/p&gt;

</description>
      <category>webdev</category>
      <category>testing</category>
    </item>
    <item>
      <title>Typed translations in Angular</title>
      <dc:creator>Noda</dc:creator>
      <pubDate>Wed, 08 Nov 2023 08:28:58 +0000</pubDate>
      <link>https://dev.to/noda/typed-translations-in-angular-371c</link>
      <guid>https://dev.to/noda/typed-translations-in-angular-371c</guid>
      <description>&lt;p&gt;&lt;em&gt;How to Improve Angular Application Build Quality and Enhance Key Verification with ngx-translate or transloco&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;By &lt;a href="https://www.linkedin.com/in/max-dolgikh/" rel="noopener noreferrer"&gt;Maksim Dolgikh&lt;/a&gt;, Senior Front End Developer at &lt;a href="https://noda.live/" rel="noopener noreferrer"&gt;Noda&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Supporting internationalization is one of the challenging topics in front-end development, everyone always adds only keys and values for the primary locale, usually English (&lt;code&gt;en&lt;/code&gt; or &lt;code&gt;en-gb&lt;/code&gt;), leaving translations for other languages for later.&lt;/p&gt;

&lt;p&gt;We encountered this issue on one of our projects while implementing localization.&lt;/p&gt;

&lt;p&gt;In the initial version, we did not configure the localization settings, completed the build, and obtained the result.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jdgz3fqg36tbsa1aj66.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8jdgz3fqg36tbsa1aj66.gif" alt="broken-i18n-tokens"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Translations by token, in case of failure, were replaced with the token name.&lt;/p&gt;

&lt;p&gt;The hotfix for the problem is to use a fallback language (&lt;code&gt;fallbackLang&lt;/code&gt;) when resolving translations by token.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figyiy8san9uwooix3pf8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Figyiy8san9uwooix3pf8.gif" alt="brokent-i18n-fallbackLang"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;fallbackLang&lt;/code&gt; solves the issue of displaying text so as not to confuse the user, but there's still a need to monitor the presence of keys, and also involve QA to detect problems.&lt;/p&gt;

&lt;p&gt;Many who use runtime translations fully understand the problem of, "&lt;em&gt;how can you ensure that the key-token is correct and will find the corresponding translation for the current locale at browser runtime?&lt;/em&gt;"&lt;/p&gt;

&lt;p&gt;I too wondered about this, but all I managed to find was an article from October 21, 2018. &lt;a href="https://medium.com/angular-in-depth/angular-typed-translations-29353f0a60bc" rel="noopener noreferrer"&gt;Typed translations in Angular&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The solution was excellent for that time, but the author uses the object directly, and native pluralization through js with the presence of ICU seems excessive.&lt;/p&gt;

&lt;p&gt;Undoubtedly, this solution could have been improved, for instance, by making the &lt;code&gt;TRANSLATION&lt;/code&gt; token a stream and adding an aggregator service with translations upon language change, and so on. &lt;em&gt;But then again, that's a whole different story.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  ESLINT - i18n-json
&lt;/h3&gt;

&lt;p&gt;The situation is partly saved by the eslint plugin &lt;a href="https://github.com/godaddy/eslint-plugin-i18n-json" rel="noopener noreferrer"&gt;eslint-plugin-i18n-json&lt;/a&gt;, which checks the identity of the keys in json files, but it's also not enough for reliability.&lt;/p&gt;

&lt;p&gt;Because it's a one-sided check, and it doesn't guarantee that the developer, using the current translation base, will specify the correct key, and QA will notice it if something goes wrong.&lt;/p&gt;

&lt;p&gt;We will need to install &lt;code&gt;eslint&lt;/code&gt;, &lt;code&gt;commitlint&lt;/code&gt; to check changes in json, and also integrate it into pipelines if we have translations embedding from external sources.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Proposal
&lt;/h3&gt;

&lt;p&gt;What if I told you that all these checks are unnecessary?&lt;/p&gt;

&lt;p&gt;To ensure the consistency of translations under a locale, forget about &lt;code&gt;fallbackLang&lt;/code&gt; and &lt;code&gt;missingKeyHandler&lt;/code&gt;, and no longer worry about the correctness of the key, can it be achieved solely with typescript?&lt;/p&gt;

&lt;p&gt;This solution is suitable both for current implementations on &lt;a href="https://www.npmjs.com/package/@ngx-translate/core" rel="noopener noreferrer"&gt;ngx-translate&lt;/a&gt; or &lt;a href="https://www.npmjs.com/package/@ngneat/transloco" rel="noopener noreferrer"&gt;transloco&lt;/a&gt; and for new ones.&lt;/p&gt;

&lt;p&gt;So, what requirements should the solution meet?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The application build fails if a key is missing in one of the translations.&lt;/li&gt;
&lt;li&gt;Developers are notified of errors with an incorrect key, and there are hints about the available list of keys.&lt;/li&gt;
&lt;li&gt;Ensure scalability by adding new translations by locale, without direct interaction with the code, but provide all checks.&lt;/li&gt;
&lt;li&gt;Current key translations for &lt;code&gt;ngx-translate&lt;/code&gt; and &lt;code&gt;transloco&lt;/code&gt; work as before. They can be parameterized, and they support ICU.&lt;/li&gt;
&lt;li&gt;Translations can be used in libraries, and they can be published as self-sufficient packages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Secondary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;QA, through the browser console, can understand which element interacts with which key.&lt;/li&gt;
&lt;li&gt;Exclude switching to a locale if it's not on the list of available ones.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Solution
&lt;/h2&gt;

&lt;p&gt;The demonstration repository consists of:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assets&lt;/code&gt; - a directory with a subdirectory i18n, where translation files are stored.&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;libs&lt;/code&gt; - a set of libraries for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ui-actions&lt;/code&gt; and &lt;code&gt;ui-layouts&lt;/code&gt; - a set of demo-libs.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;i18n-wrapper&lt;/code&gt; - contains entities for typing the transloco service.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;typed-transloco&lt;/code&gt; - a typed version of transloco with its translation file and based on i18n-wrapper.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;src&lt;/code&gt; - directory of the host application.&lt;/p&gt;&lt;/li&gt;

&lt;li&gt;&lt;p&gt;&lt;code&gt;scripts&lt;/code&gt; - directory for service scripts.&lt;/p&gt;&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff79ig5igckqarxhoxpl0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff79ig5igckqarxhoxpl0.png" alt="repo-structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For simplicity and convenience, I decided to base my solution on the library &lt;code&gt;@ngneat-transloco&lt;/code&gt;, which is common for the two repository libraries.&lt;br&gt;
It provides a unified translation file and a service with which they interact.&lt;/p&gt;

&lt;p&gt;In the case of publishing UI libraries, this library will also be published and will serve as a peer dependency.&lt;/p&gt;

&lt;p&gt;This solution is more suitable for large monorepositories where translations are managed through a core library with &lt;code&gt;assets/i18n&lt;/code&gt;. Nothing prevents my solution from being applied to &lt;code&gt;ngx-translate&lt;/code&gt;, where there is a mechanism for service inheritance or separation.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Library i18n-wrapper
&lt;/h3&gt;

&lt;p&gt;This library will contain two directories:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;transloco&lt;/code&gt; - a directory for transloco wrappers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;types&lt;/code&gt; - common types for typing the translation file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58n6qdfzoq6owujuhjwf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F58n6qdfzoq6owujuhjwf.png" alt="i18n-wrapper-structure"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Typing tokens for translation
&lt;/h4&gt;

&lt;p&gt;We are accustomed to specifying a translation token as a string in the form of keys separated by a dot. Example: &lt;code&gt;lib.scope.module.component.somekey&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I wanted to maintain this approach and create a type that calculates all possible keys from our unified translation file.&lt;/p&gt;

&lt;p&gt;I decided to base such a type on the recursive type presented in an article by &lt;a href="https://medium.com/javascript-in-plain-english/type-challenges-implement-the-objectkeypaths-utility-type-e49e79bb4b48" rel="noopener noreferrer"&gt;@bytefer&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Unlike the universal version in the article, I will trim this recursive type for our solution, so it provides only the final paths through a dot to the primitive.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TAddPrefix&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Prefix&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Key&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
 &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
 &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;.&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TObjectKeyPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Prefix&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;
   &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;TObjectKeyPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;TAddPrefix&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
     &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;TAddPrefix&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Prefix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;P&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
     &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;never&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}[&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;T&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Having a recursive type to retrieve translation paths, all that's left for us to do is to create a type that transforms the readonly type from &lt;code&gt;i18n.db.ts&lt;/code&gt; to a key map for each locale, ensuring synchronization between languages.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TTranslatePath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
 &lt;span class="nx"&gt;DB&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;object&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nx"&gt;Langs&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;DB&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;TObjectKeyPaths&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;Langs&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;With these two types, we've obtained the CORE part of our typing, which addresses 80% of the issues from the posed problem, which can already be applied to different parts of the project, not just to localization.&lt;/p&gt;

&lt;p&gt;Only 20% remains - a typed wrapper for transloco.&lt;/p&gt;

&lt;p&gt;There will be only three wrappers, and all of them are abstract:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;AbstractTranslocoConfigService&lt;/code&gt; - a service regulating the list of available languages when providing settings for &lt;code&gt;TRANSOLO_CONFIG&lt;/code&gt;. It also implements the &lt;code&gt;TranslocoLoader&lt;/code&gt; interface to load our translation file.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AbstractTranslocoService&lt;/code&gt; - a service wrapper over TranslocoService, which offers a similar list of methods from TranslocoService, but at the same time narrows down the types of available languages and keys to those available from &lt;code&gt;i18n.db.ts&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AbstractTranslocoComponent&lt;/code&gt; - one of the entities that will inject translations into the template based on the provided token (similar to pipe and directive).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  AbstractTranslocoConfigService
&lt;/h4&gt;

&lt;p&gt;As I mentioned earlier, it is necessary to provide functions for the &lt;code&gt;TRANSLOCO_CONFIG&lt;/code&gt; and &lt;code&gt;TRANSLOCO_LOADER&lt;/code&gt; tokens when values are delivered through a factory.&lt;/p&gt;

&lt;p&gt;This service is straightforward and will accept one generic from the type of our translation file for typing the available list of languages.&lt;/p&gt;

&lt;p&gt;Since we know the available list of languages, and we get the default language in the constructor, for the method providing the config, we can exclude &lt;code&gt;defaultLang&lt;/code&gt;, &lt;code&gt;availableLangs&lt;/code&gt;, and &lt;code&gt;fallbackLang&lt;/code&gt;, leaving settings for transloco.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;TTypedTranslocoConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nb"&gt;Omit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TranslocoConfig&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;defaultLang&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;availableLangs&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fallbackLang&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Result&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractTranslocoConfigService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
   &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;TranslocoLoader&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;AVAILABLE_LANGS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;


   &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AVAILABLE_LANGS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Array&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Set&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
               &lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
               &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
           &lt;span class="p"&gt;]),&lt;/span&gt;
       &lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getProvidedConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TTypedTranslocoConfig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;TranslocoConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;patchedConfig&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Partial&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TranslocoConfig&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="p"&gt;...&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;defaultLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;initializeDefaultLanguage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;availableLangs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AVAILABLE_LANGS&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt;
           &lt;span class="na"&gt;fallbackLang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;


       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;translocoConfig&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;patchedConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;initializeDefaultLanguage&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browserLanguage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getBrowserLang&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;browserLanguage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;


       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAvailableLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browserLanguage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;browserLanguage&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;




   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;isAvailableLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AVAILABLE_LANGS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getTranslation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DB&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  AbstractTranslocoService
&lt;/h4&gt;

&lt;p&gt;This service doesn't contain any particular logic and serves as a typed intermediary between entities wanting to use the &lt;code&gt;TranslocoService&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For simplicity and to minimize code, I've only added methods for language management.&lt;/p&gt;

&lt;p&gt;The only distinctive feature of this service from the native &lt;code&gt;TranslocoService&lt;/code&gt; is the filtering of languages based on the &lt;code&gt;AbstractTranslocoConfigService&lt;/code&gt; to avoid setting an unavailable language.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractTranslocoService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
   &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


   &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TranslocoService&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="na"&gt;translocoConfigService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AbstractTranslocoConfigService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getActiveLang&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveLang&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;setActiveLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setActiveLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getDefaultLang&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getDefaultLang&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;setDefaultLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setDefaultLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;checkLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;getAvailableLangs&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getAvailableLangs&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;


   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nf"&gt;checkLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;language&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;


       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoConfigService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAvailableLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;language&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;


       &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="na"&gt;browserLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;getBrowserLang&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browserLanguage&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoConfigService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;isAvailableLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browserLanguage&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browserLanguage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;


       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getActiveLang&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;translocoConfigService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DEFAULT_LANG&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h4&gt;
  
  
  AbstractTranslocoComponent
&lt;/h4&gt;

&lt;p&gt;I've chosen to implement this through a component, and this choice is deliberate for several reasons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It allows us not to declare functions in the template, which could be restricted by eslint rules.&lt;/li&gt;
&lt;li&gt;There's an option to detach the component from the component tree for optimization when switching languages.&lt;/li&gt;
&lt;li&gt;For QA purposes, there's the possibility to bind our token to an element using HostBinding, allowing for identification of which token is being used in a particular location.&lt;/li&gt;
&lt;li&gt;Auto-suggestions for available tokens are provided.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cons:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;There's a need to specify the complete key from the translation file.&lt;/li&gt;
&lt;li&gt;It's impossible to pass the value from one component to others that accept text only in the string format and don't allow customization via &lt;code&gt;&amp;lt;ng-content&amp;gt;&lt;/code&gt; or &lt;code&gt;TemplateRef&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fortunately, these drawbacks are addressed by creating wrappers for the translocoPipe and translocoDirective.&lt;/p&gt;

&lt;p&gt;To reduce coupling, I will introduce an interface named &lt;code&gt;ISelectTranslateService&lt;/code&gt;, which will regulate the service implementation for translations based on parameters.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;ISelectTranslateService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
   &lt;span class="nx"&gt;i18nDB&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;selectTranslate&lt;/span&gt;&lt;span class="na"&gt;$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TTranslatePath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i18nDB&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Result&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Directive&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AbstractTranslocoComponent&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;
 &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nb"&gt;Record&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Translation&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;keyof&lt;/span&gt; &lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;OnChanges&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="nx"&gt;update$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;ReplaySubject&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;void&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;


 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;translation$&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;asObservable&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;pipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="nf"&gt;switchMap&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getCurrentTranslation&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
 &lt;span class="p"&gt;);&lt;/span&gt;


 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TTranslatePath&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;


 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;HashMap&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


 &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


 &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ISelectTranslateService&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i18nDb&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;Lang&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;


 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ngOnChanges&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;


 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;


 &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;getCurrentTranslation&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nx"&gt;Observable&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;service&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;selectTranslate&lt;/span&gt;&lt;span class="nf"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="c1"&gt;// @ts-expect-error: not be infinite&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;
   &lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;(&lt;a href="https://github.com/Misterion96/typed-i18n/blob/main/libs/i18n-wrapper/src/lib/transloco/abstract/abstract-transloco-detach.component.ts" rel="noopener noreferrer"&gt;advanced implementation&lt;/a&gt; with detach and HostBinding)&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Library typed-transloco
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Unified Translation Database
&lt;/h4&gt;

&lt;p&gt;Firstly, I'd like to move away from the usual practice of placing translations under each locale in json to a single ts file.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assets/i18n/en.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"back"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Back"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"confirm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Are you sure?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"New"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"layouts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"about"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"About"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Account"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"app_store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"App Store"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;assets/i18n/de.json&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"actions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"back"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Zurück"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"confirm"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bist du sicher?"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"new"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Neu"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="nl"&gt;"layouts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"about"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Um"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"account"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Konto"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="nl"&gt;"app_store"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Appstore"&lt;/span&gt;&lt;span class="w"&gt;
 &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It exports a single object with all translations under each locale.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ss5toq4wgny0lmxk4rw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F2ss5toq4wgny0lmxk4rw.png" alt="unifier-schema"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;i18n.db.ts&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;TRANSLATE_DB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;back&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Zurück&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Bist du sicher?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Neu&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;layouts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Um&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Konto&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app_store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Appstore&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;},&lt;/span&gt;
 &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;actions&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;back&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Back&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;confirm&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Are you sure?&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;New&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;layouts&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;about&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;About&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Account&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;app_store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App Store&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Essentially, yes, I'm moving away from lazily loaded translations towards synchronous loading and predictable typing.&lt;/p&gt;

&lt;p&gt;Certainly, you can import JSON files into TS, but then you'd have to configure &lt;code&gt;tsconfig.json&lt;/code&gt; for &lt;code&gt;resolveJsonModule&lt;/code&gt;. Also, for personal reasons, I find this approach suboptimal if there's a process for exporting a single translation file from the project.&lt;/p&gt;

&lt;h4&gt;
  
  
  Typed Entities
&lt;/h4&gt;

&lt;p&gt;With the presence of a single translation file and abstract wrappers, we can implement typed versions for our translations:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TypedTranslocoConfigService
```typescript
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;@Injectable()&lt;br&gt;
export class TypedTranslocoConfigService extends AbstractTranslocoConfigService {&lt;br&gt;
   constructor() {&lt;br&gt;
       super(TRANSLATE_DB, 'en');&lt;br&gt;
   }&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
- TypedTranslocoService
```typescript


@Injectable()
export class TypedTranslocoService extends AbstractTranslocoService&amp;lt;typeof TRANSLATE_DB&amp;gt;{
   constructor(
       translocoService: TranslocoService,
       typedTranslocoConfigService: TypedTranslocoConfigService
   ) {
       super(translocoService, typedTranslocoConfigService);
   }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;TypedTranslocoComponent
```typescript
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;@Component({&lt;br&gt;
 selector: 'typed-transloco-component',&lt;br&gt;
 standalone: true,&lt;br&gt;
 imports: [CommonModule],&lt;br&gt;
 template: '{{ translation$ | async }}',&lt;br&gt;
 changeDetection: ChangeDetectionStrategy.OnPush,&lt;br&gt;
})&lt;br&gt;
export class TypedTranslocoComponent extends AbstractTranslocoComponent{&lt;br&gt;
 constructor(&lt;br&gt;
     public typedTranslocoService: TypedTranslocoService&lt;br&gt;
 ) {&lt;br&gt;
   super(typedTranslocoService);&lt;br&gt;
 }&lt;br&gt;
}&lt;/p&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
#### TypedTranslocoModule

It will also be required to declare all the created services and provide the necessary values when we want to use translations.

```typescript


@NgModule({
   imports: [TranslocoModule],
   providers: [TranslocoService]
})
export class TypedTranslocoModule {
   static forRoot(config: TTypedTranslocoConfig = {}): ModuleWithProviders&amp;lt;TypedTranslocoModule&amp;gt; {
       return {
           ngModule: TypedTranslocoModule,
           providers: [
               TypedTranslocoService,
               TypedTranslocoConfigService,
               {
                   provide: TRANSLOCO_LOADER,
                   useExisting: TypedTranslocoConfigService,
               },
               {
                   provide: TRANSLOCO_CONFIG,
                   deps: [TypedTranslocoConfigService],
                   useFactory: (configService: TypedTranslocoConfigService) =&amp;gt; {
                       return configService.getProvidedConfig(config)
                   }
               }
           ]
       }
   }
}


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  3. Integration into UI libraries
&lt;/h3&gt;

&lt;p&gt;The main objective of this article is to demonstrate a solution for typing translations, so the examples for these libraries will be simple and contain minimal logic.&lt;/p&gt;

&lt;p&gt;For this purpose, a showcase component was created in each of them.&lt;/p&gt;

&lt;p&gt;Both components, conditionally, display a list of available components from the library for the user, similar to the storybook.&lt;/p&gt;

&lt;p&gt;I only interact with the component template and will create one element that supports typed localization for now.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrqezup0yesxltnnkbdk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzrqezup0yesxltnnkbdk.png" alt="i18n-autocomplete-token"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Since we passed the computed type from &lt;code&gt;TRANSLATE_DB&lt;/code&gt; when creating our component, the code editor can already suggest to us which available tokens we have for translation.&lt;/p&gt;

&lt;p&gt;This also works for the list of available languages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i2blvgpjiu9f54zvxn3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4i2blvgpjiu9f54zvxn3.png" alt="i18n-autocomplete-lang"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When attempting to specify an incorrect token, the editor will highlight a warning indicating that we have specified the key incorrectly. We will deliberately leave this issue uncorrected.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa04u7t2akd60128fqwri.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fa04u7t2akd60128fqwri.png" alt="i18n-autocomplete-token-error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Result&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ui-actions library&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"actions.back"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"actions.confirm"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"actions.new-wrong"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;ui-layouts library&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"layouts.app_store"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"layouts.account"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;span class="nt"&gt;&amp;lt;button&amp;gt;&lt;/span&gt;
   &lt;span class="nt"&gt;&amp;lt;typed-transloco-component&lt;/span&gt; &lt;span class="na"&gt;key=&lt;/span&gt;&lt;span class="s"&gt;"layouts.about"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/typed-transloco-component&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/button&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Using libraries in an application
&lt;/h3&gt;

&lt;p&gt;You can't showcase the localization in libraries without using a demo application. It will be small and contain minimal code.&lt;/p&gt;

&lt;p&gt;Displays our two components from the libraries, as well as switches the language through the &lt;code&gt;TypedTranslocoService&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;

&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Component&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
 &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;app-root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`
   &amp;lt;lib-actions-showcase&amp;gt;&amp;lt;/lib-actions-showcase&amp;gt;
   &amp;lt;lib-layouts-showcase&amp;gt;&amp;lt;/lib-layouts-showcase&amp;gt;
   &amp;lt;div&amp;gt;
     &amp;lt;button (click)="onChangeLang('en')"&amp;gt;EN&amp;lt;/button&amp;gt;
     &amp;lt;button (click)="onChangeLang('de')"&amp;gt;DE&amp;lt;/button&amp;gt;
   &amp;lt;/div&amp;gt;
 `&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="na"&gt;styles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;`:host {display: flex; flex-direction: column; gap: 8px}`&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AppComponent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nx"&gt;typedTranslocoService&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;TypedTranslocoService&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;


 &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;onChangeLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;lang: &lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;typedTranslocoService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setActiveLang&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;In addition to importing the library components, the localization module is imported with forRoot to register all necessary services.&lt;/p&gt;

&lt;p&gt;When trying to launch our application, we encounter an &lt;strong&gt;error&lt;/strong&gt; 🔥.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq4zlkaym8yrh809dx5x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftq4zlkaym8yrh809dx5x.png" alt="build-i18n-error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the result we've been striving for throughout the entire article - we catch errors from incorrect tokens and ensure typing.&lt;/p&gt;

&lt;p&gt;Let's fix the error 🚀&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dfu3q8i2hoxwbd48r37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5dfu3q8i2hoxwbd48r37.png" alt="i18n-autocomplete-token-fixed"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And let's rebuild the application. It successfully compiled 🎉🎉🎉, and now we can switch to the browser to see the final result.&lt;/p&gt;

&lt;p&gt;And our localization works.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8lq9htr3cxcr6x52ez4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx8lq9htr3cxcr6x52ez4.gif" alt="runtime-i18n-showcase"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Final result
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc44y8dm8tet2gqu66zq.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsc44y8dm8tet2gqu66zq.gif" alt="final-result"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;a href="https://github.com/Misterion96/typed-i18n" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Next Article
&lt;/h2&gt;

&lt;p&gt;In the next article, I'll discuss how to eliminate the need to synchronize keys between translation maps across locales by implementing "file replacement" for libraries. I'll also showcase a fully automated system for localizing an application based on a single translation map for the desired locales through CI.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;About Noda&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;a href="https://noda.live/" rel="noopener noreferrer"&gt;Noda&lt;/a&gt; is a global, multi-currency open banking solution for seamless business transactions. It currently operates with 1,650 banks across 28 countries, encompassing 283 bank brands with over 30,000 branches.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Noda enables merchants to receive direct bank payments from eCustomers via Open Banking as an alternative to cards. Merchants can implement Open Banking payments quickly via Noda API, making use of their intuitive UX and lower fees.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>angular</category>
      <category>transloco</category>
      <category>i18n</category>
      <category>localization</category>
    </item>
    <item>
      <title>How to Boost SEO for Startups: 4 SEO Tips to Grow Your Business</title>
      <dc:creator>Noda</dc:creator>
      <pubDate>Mon, 25 Sep 2023 10:20:56 +0000</pubDate>
      <link>https://dev.to/noda/how-to-boost-seo-for-startups-4-seo-tips-to-grow-your-business-4ild</link>
      <guid>https://dev.to/noda/how-to-boost-seo-for-startups-4-seo-tips-to-grow-your-business-4ild</guid>
      <description>&lt;p&gt;Life may seem tough for startups, especially in the realm of Social Engine Optimisation (SEO). With our brand-new websites and consequently low domain authority, it proves more difficult to get to the top of Google’s hierarchy. That’s why startups have to create a complete on-page/off-page SEO strategy and identify the key strengths of their products and services to focus on.&lt;/p&gt;

&lt;p&gt;Being a startup ourselves, at &lt;a href="https://noda.live/"&gt;Noda&lt;/a&gt; we have increased our Domain Rating by 200% in a few months. We’ve done it using our “white” off-page SEO tactics, detailed analysis of the external sources and growing popularity on the Internet.&lt;/p&gt;

&lt;p&gt;Here we’ve gathered some of the key tips and valuable insights into the best SEO practises and strategies as a new business. &lt;/p&gt;

&lt;h2&gt;
  
  
  Primary SEO Concerns for Startups
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Limited Budget and Resources
&lt;/h3&gt;

&lt;p&gt;Unlike established companies, startups often operate on a shoestring budget. Allocating a sizable chunk to SEO can be a challenge. They often grapple with the decision of whether to invest in paid search marketing (like Google Ads) or organic SEO or strike a balance between the two.&lt;/p&gt;

&lt;h3&gt;
  
  
  Immediate Results vs. Long-Term Strategy
&lt;/h3&gt;

&lt;p&gt;Startups, especially those with investor backing, are under pressure to show growth and traction. SEO typically offers long-term benefits, and startups are often concerned about the duration it will take to see tangible results.&lt;/p&gt;

&lt;h3&gt;
  
  
  Measuring ROI
&lt;/h3&gt;

&lt;p&gt;Understanding which strategies are working and offering a good return on investment (ROI) is crucial. Startups often struggle to set up the right metrics and KPIs to measure their SEO success.&lt;/p&gt;

&lt;h3&gt;
  
  
  New website challenges
&lt;/h3&gt;

&lt;p&gt;Usually, startup websites are new and have low parameters due to their youth. It takes time to raise domain authority and ratings with off-page SEO. After creating a content strategy, it may take a while to start ranking for queries, find out what type of content performs better and why, attract organic traffic, and gain the trust of Google’s algorithms. &lt;/p&gt;

&lt;h3&gt;
  
  
  Budget
&lt;/h3&gt;

&lt;p&gt;The budget can vary, depending on how much the company is willing to invest in SEO. That’s why teams must find the best way to spend this budget with visible results. For example, on link-building and high-quality content. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--r4R82qtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/io4idg9x7v88ikpy7v9a.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--r4R82qtc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/io4idg9x7v88ikpy7v9a.jpg" alt="Image description" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip #1: Determine Your Budget
&lt;/h2&gt;

&lt;p&gt;Before allocating any funds, startups need to determine their immediate SEO needs. Is it a site overhaul for SEO optimisation? Do they need more content? Or is link-building the focus? By prioritising their needs, startups can allocate funds more effectively.&lt;/p&gt;

&lt;p&gt;Some SEO expenses are fixed, like monthly subscriptions to SEO tools or retainer fees for agencies. Other costs, like content creation or link-building campaigns, can vary. It's essential to categorise these costs to avoid overshooting the budget.&lt;/p&gt;

&lt;p&gt;If content creation is outsourced, startups need to decide on the frequency (e.g., weekly, bi-weekly) and type of content (blog posts, videos, infographics). Costs can vary widely based on these factors.&lt;/p&gt;

&lt;p&gt;Budgeting decisions should be tied closely to expected ROI. If a particular strategy or channel yields good returns, it might make sense to allocate more funds there, even if it wasn't part of the initial plan.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip #2: Conduct Competitor Analysis
&lt;/h2&gt;

&lt;p&gt;Competitor analysis usually starts by evaluating the website metrics like Domain Rating/Domain Authority, traffic, top organic keywords, top pages, website structure, visual elements, and more. Based on at least 5-10 biggest competitors SEO teams can form a clear picture of their company’s niche.&lt;/p&gt;

&lt;p&gt;Start by listing companies that offer similar products or services. Not all direct business competitors will be SEO competitors, and vice versa. Tools like SEMrush or Ahrefs can help identify websites that rank for similar keywords.&lt;/p&gt;

&lt;p&gt;Examine which keywords competitors are targeting and how they rank. Look at both short-tail and long-tail keywords. This can reveal gaps in your keyword strategy and present opportunities for targeting less competitive, high-ROI terms.&lt;/p&gt;

&lt;p&gt;Examine the quality and quantity of backlinks pointing to competitor websites. Tools like Moz or Ahrefs can help with this task. A robust backlink profile can significantly boost domain authority. By understanding where competitors are getting their links, startups can identify potential backlink opportunities.&lt;/p&gt;

&lt;p&gt;For startups targeting local audiences, it's crucial to analyse competitors' local SEO strategies. This includes examining their Google My Business listings, local backlinks, reviews, and local keyword rankings.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip #3: Prioritise UX
&lt;/h2&gt;

&lt;p&gt;Since Google started using basic UX metrics in the ranking, life has become somewhat harder. Generally speaking, badly designed sites had to be cleaned up, for example, by enlarging clickable areas and providing adequate contrast. &lt;/p&gt;

&lt;p&gt;Although for well-designed sites it’s business as usual, the page load time metric hit everybody. Only very specialised businesses can still be hosted traditionally, the rest (those with competition) had to invest in geolocalised hosting to make their website faster, regardless of the country.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tip #4: Advanced Keyword Research
&lt;/h2&gt;

&lt;p&gt;Keyword research is one of the most important tasks when it comes to SEO strategy and implementation.&lt;br&gt;
Startups can use special SEO tools like Ahrefs and KWFinder by Mangools. They can analyse their competitors’ pages among top Google results. &lt;/p&gt;

&lt;p&gt;Paying attention to what keywords the competitors are ranking for is important, as well as noting phrase variations in copy. Other tactics include evaluating LSI (Latent Semantic Indexing), looking for words repeated on different pages, and counting approximate text length.&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding Fast-Ranking Keywords
&lt;/h3&gt;

&lt;p&gt;Long-tail keywords, typically three or more words in length, tend to have lower search volumes but also less competition. This makes them easier to rank for. They often have a higher conversion rate too, since they're more specific.&lt;/p&gt;

&lt;p&gt;Tools like Ubersuggest, Ahrefs, SEMrush, and Google Keyword Planner can be invaluable. They allow you to find keyword variations, assess competition levels, and gauge search volumes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keyword Difficulty
&lt;/h3&gt;

&lt;p&gt;Some keyword research tools, like Ahrefs, provide a 'Keyword Difficulty' score. This score gives an estimate of how hard it would be to rank in the top 10 search results for that keyword. Ideally, startups should target keywords with lower difficulty scores.&lt;/p&gt;

&lt;p&gt;See which keywords your competitors rank for, especially those not in the top spots but on the first page. These can be potential targets if you believe you can produce better content or a more relevant offer.&lt;/p&gt;

&lt;p&gt;Some keywords might offer quick wins in terms of rankings but not drive valuable traffic. Ensure the keywords you prioritise align with your business goals and user needs.&lt;br&gt;
Final Thoughts&lt;/p&gt;

&lt;p&gt;For startups, navigating the SEO landscape­ may seem overwhe­lming, especially with limited re­sources and the pressure­ for immediate results. Howe­ver, by adopting a strategic approach, startups can effe­ctively harness the powe­r of SEO to their advantage. &lt;/p&gt;

&lt;p&gt;It all starts with establishing cle­ar budgets and conducting thorough competitor analysis. Prioritisng user e­xperience is ke­y, as well as utilising advanced keyword re­search techniques. &lt;/p&gt;

&lt;p&gt;Taking inspiration from &lt;a href="https://noda.live/"&gt;Noda's&lt;/a&gt; growth, it's evident that a we­ll-executed SEO strate­gy, combined with a deep unde­rstanding of one's niche and target audie­nce, can lead to substantial returns and lay the­ groundwork for long-term success in the digital re­alm.&lt;/p&gt;

</description>
      <category>seo</category>
      <category>marketing</category>
      <category>promotion</category>
      <category>startup</category>
    </item>
  </channel>
</rss>
