Skip to main content

Command Palette

Search for a command to run...

Native TypeScript'te, i18next ile Yerelleştirme (Localization) Uygulaması

Popüler bir yerelleştirme kütüphanesi olan i18next'i, Native TypeScript ile web projemizde uygulamayı görüyoruz.

Published
4 min read
Native TypeScript'te, i18next ile Yerelleştirme (Localization) Uygulaması

Yerelleştirme, kısaca web sitemizin içeriğinin (herhangi bir yazı, makale veya kullanıcının web siteyle etkileşimlerini yönlendiren her türden metinsel bilgi), kullanıcının makinesindeki dil tercihlerine göre değişip uyarlanmasıdır. Bunun gerçekleştirmek için pek çok yol var fakat biz oldukça kabul gören ve yaygın bir kütüphane olan i18next ile bu localization işlemini gerçekleştireceğiz. i18next, JSON olarak aldığı çeviri verilerini, daha önce dediğim gibi, kullanıcının makinesindeki dil tercihlerine göre dinamik olarak değiştiren bir kütüphanedir ve oldukça basit bir yerelleştirme çözümü sunar. Bunu hem tarayıcı tarafında (client-side) hem de sunucu tarafında (server-side) yapabilir fakat biz bu yazıda client-side kullanımı esas alacağız. Ayrıca hiçbir ek kütüphane (React, Vue vs.) kullanmadan gerçekleştireceğiz.

Gerekli bileşenlerin indirilmesi

Öncelikle bir TypeScript projesi oluşturduğunuzu varsayıyorum. Kısaca i18next için gerekli olan kütüphaneleri aşağıdaki gibi indirerek projenize kurabilirsiniz:

PS C:\Users\gokacinlar\Desktop\proje> npm install --save i18next i18next-browser-languagedetector
PS C:\Users\gokacinlar\Desktop\proje> npm install -D i18next-resources-for-ts @types/i18next
# i18next-resources-for-ts kütüphanesini bir development dependency olarak eklememiz gerekli
# nihai çıktıda gerekli olmayacaktır.

# i18next -> Temel kütüphane
# i18next-browser-languagedetector -> Kullanıcının dil tercihlerine göre işlem yapacağımız kütüphane
# i18next-resources-for-ts -> i18next'in esas aldığı JSON formatındaki dilleri, type-safe olarak
# kullanmamızı sağlayan kütüphane
# @types/i18next -> TypeScript için gerekli i18next tipleri

Dillerimizi barındıran JSON dosyalarının projeye eklenmesi

Projemiz içerisinde, ismi “locales” olan bir dosya oluşturalım ve içine şimdilik “en” ve “tr” isimli iki adet alt dosya oluşturarak JSON formatında i18next’in kullanabileceği dil dosyalarımızı koyalım. Burada oluşturacağımız dosyalar her bir dil için toplamda iki tanedir: <dil>.json ve fallback.json:

Bu dosyalarımızın içeriği sizin projenizde kullanacağınız çeviri tercihlerine göre değişkenlik gösterebilir ama ben örnek olması açısından aşağı yukarı size uyabilecek şöyle basit bir girdi yazdım (bu kendi sitemde kullandığımız basit bir örnektir):

{
    "hero": {
        "greet": "Merhaba! Ben",
        "buttons": {
            "workWMe": "Benimle Çalışın",
            "cv": "CV'mi İndirin"
        }
    },
    "title": "İngilizce Öğretmeni & Ön-yüz Geliştiricisi",
    "description": {
        "part1": "x",
        "part2": "y"
    }
}

JSON ile girdi olarak alabileceğiniz veri miktarı ise sizin hayal gücünüze ve projenizin imkanlarına göre son derece çeşitli olabilir.

Temel i18Next sınıfının yazılması

Bileşenlerimizi indirdiğimize ve temel proje kurulumunu yaptığımıza göre, dil dosyalarımızı projemizde i18next ile kullanabileceğimiz bir sınıf yazalım (dosyamızın ismi i18n.ts olsun).

Eğer sınıfımızı yazacağımız TypeScript dosyasının ismi, node_modules isimli dosyada kullandığımız i18next kütüphanesi ile aynı olursa (i18next.ts) TypeScript derlemesi hata verebilir. Sınıfımızı yazacağımız dosya mümkünse farklı bir isimde olsun.
// Öncelikle kütüphanelerimizi ve JSON dosyalarımızı import edelim
import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
// İngilizce
import EnNs1 from "./locales/en/en.json";
import EnFallback from "./locales/en/fallback.json";
// Türkçe
import TrNs1 from "./locales/tr/tr.json";
import TrFallback from "./locales/tr/fallback.json";
// Daha sonra i18next'in kullanacağı dil dosyalarını, kaynak (resources) olarak belirleyip
// basit bir interface yazalım
interface Resources {
    [key: string]: {
        [namespace: string]: any;
    };
}

const resources: Resources = {
    en: {
        ns1: EnNs1,
        fallback: EnFallback,
    },
    tr: {
        ns1: TrNs1,
        fallback: TrFallback,
    },
};

Bu adımları yaptıktan sonra, i18next dokümantasyonunda yazıldığı üzere basit bir konfigürasyon ile sınıfımızı yazalım:

class Localize {
    private static initI18n(): void {
        i18next
            .use(LanguageDetector) // Dil detektörünü kullanalım
            .init({
                debug: false,
                fallbackLng: "en", // Dil yerelleştirmesi olmazsa, fallback dilimizi belirleyelim
                defaultNS: "ns1",
                fallbackNS: "fallback",
                ns: ["ns1", "ns2", "fallback"],
                resources, // kaynaklarımızı resources değişkeninden alalım
                interpolation: { escapeValue: false },
                supportedLngs: ["en", "tr"],
                detection: { // Kullanıcının dilini hangi yönden öğreneceğimizi yazalım
                    order: ["querystring", "cookie", "localStorage", "navigator", "htmlTag"],
                    lookupQuerystring: "lng",
                    lookupCookie: "i18next",
                    lookupLocalStorage: "i18nextLng",
                    caches: ["localStorage", "cookie"],
                },
            });
    }

    // i18next'i initialize edelim
    public static init(): void {
        this.initI18n();
    }

    // i18next'i, başka bir dosyada kullanacağımız translate metodumuzu yazalım
    public static translate(key: string): string {
        if (typeof key !== "string") {
            throw new Error("Input type for i18next localization must be string.");
        }
        return i18next.t(key);
    }
}

export default Localize;

Type-Safe Kurulumun Yapılması ve CLI işlemleri

Şu ana kadar yaptığımız kurulum ile i18next'i projemizde kullanabilir hale getirdik. Ancak TypeScript kullanmanın en büyük avantajlarından biri olan tip güvenliğinden (type-safety) henüz tam anlamıyla yararlanamıyoruz. Çeviri anahtarlarımızı yazarken otomatik tamamlama desteği almıyor ve yanlış bir anahtar yazdığımızda TypeScript bizi uyarmıyor.

İşte tam bu noktada i18next-resources-for-ts kütüphanesi devreye giriyor. Bu kütüphane, JSON formatındaki dil dosyalarımızdan TypeScript tip tanımları oluşturarak, çeviri anahtarlarımızı kullanırken tam tip güvenliği ve IDE desteği sağlıyor. Böylece translate("hero.greet") yazacağımızda IDE'miz bize mevcut tüm anahtarları (JSON dosyamızda girdi olarak kullandığımız verileri) gösterecek ve yanlış bir anahtar yazdığımızda derleme zamanında hata alacağız.

Hızlıca bir types dosyasını projemizde oluşturalım ve ardından projemizin package.json dosyasına, bu bahsettiğimiz kütüphanede var olan CLI imkanlarından yararlanarak bir script ekleyelim:

{
  "scripts": {
    "toc": "i18next-resources-for-ts interface -i ./locales/en -o ./types/i18next.d.ts"
  }
}

Bu script'i çalıştırdığımızda, İngilizce dil dosyalarımızı baz alarak bir TypeScript tip dosyası oluşturulacak ve sonrasında types klasörü altında i18next.d.ts adında bir dosya oluşacak. Bu dosya, dil anahtarlarımızın tüm tip tanımlarını içerecek. Artık Localize.translate() metodumuzu kullanırken tam tip güvenliği ve otomatik tamamlama desteğine sahip olacağız!

Örnek Kullanım

import Localize from "./i18n";

// Uygulamanın başlangıcında i18next'i başlatalım
Localize.init();

// Artık çevirileri kullanabiliriz
const greeting = Localize.translate("hero.greet");
console.log(greeting); // Kullanıcının diline göre "Merhaba! Ben" veya "Hello! I am"

Bir sonraki yazımda görüşmek üzere!