# react-native: 共通文字列 URL: https://generaltranslation.com/ja/docs/react-native/guides/shared-strings.mdx --- title: 共通文字列 description: 複数のコンポーネントやファイルで使われる文字列を国際化する方法 --- {/* 自動生成: 直接編集せず、代わりに content/docs-templates/ のテンプレートを編集してください。 */} 共通文字列とは、アプリケーション全体の複数箇所で使われるテキスト値のことです。たとえば、ナビゲーションラベル、フォームメッセージ、設定データなどです。各所で翻訳ロジックを重複して実装する代わりに、[`msg`](/docs/react-native/api/strings/msg)を使って文字列を翻訳対象としてマークし、[`useMessages`](/docs/react-native/api/strings/use-messages)でそれらをデコードします. ## 共通コンテンツの問題 アプリ全体で使われる、次のナビゲーション設定を考えてみましょう: ```tsx // navData.ts export const navData = [ { label: 'Home', description: 'The home page', href: '/' }, { label: 'About', description: 'Information about the company', href: '/about' } ]; ``` これを国際化するには、通常は次の対応が必要になります。 1. 翻訳関数を受け取る関数に書き換える 2. すべての使用箇所を更新し、`t` を渡してその関数を呼び出す 3. そうした複雑さをコードベース全体で管理する その結果、保守コストが増え、コードも読みにくくなります。[`msg`](/docs/react-native/api/strings/msg) 関数を使えば、文字列をその場で翻訳対象としてマークし、必要なときにデコードできるため、この問題を解決できます。 ## クイックスタート 文字列のマークには [`msg`](/docs/react-native/api/strings/msg) を、デコードには [`useMessages`](/docs/react-native/api/strings/use-messages) を使用します。 ```tsx // navData.ts - 翻訳対象の文字列をマークする import { msg } from 'gt-react-native'; export const navData = [ { label: msg('Home'), description: msg('The home page'), href: '/' }, { label: msg('About'), description: msg('Information about the company'), href: '/about' } ]; ``` ```tsx // コンポーネントの使用 - マークされた文字列をデコードする import { useMessages } from 'gt-react-native'; import { navData } from './navData'; function Navigation() { const m = useMessages(); return ( ); } ``` ## 共通文字列の仕組み 共通文字列システムは、次の 2 つのフェーズで動作します。 1. **Mark フェーズ**: [`msg`](/docs/react-native/api/strings/msg) は文字列に翻訳メタデータを付与してエンコードします 2. **Decode フェーズ**: [`useMessages`](/docs/react-native/api/strings/use-messages) は文字列をデコードして翻訳します ```tsx // msg() は文字列をメタデータとともにエンコードする const encoded = msg('Hello, world!'); console.log(encoded); // "Hello, world!:eyIkX2hhc2giOiJkMjA3MDliZGExNjNlZmM2In0=" // useMessages() はデコードして翻訳する const m = useMessages(); const translated = m(encoded); // ユーザーの言語での "Hello, world!" ``` [`msg`](/docs/react-native/api/strings/msg) によるエンコード済みの文字列は直接使用できません。[`useMessages`](/docs/react-native/api/strings/use-messages) でデコードする必要があります。 ## コンポーネント [`useMessages`](/docs/react-native/api/strings/use-messages) フックを使います: ```tsx import { useMessages } from 'gt-react-native'; const encodedString = msg('Hello, world!'); function MyComponent() { const m = useMessages(); return
{m(encodedString)}
; } ``` ## decodeMsg で元の文字列を取得する ログ出力、デバッグ、比較などで、翻訳前の元の文字列にアクセスしたい場合があります。元のテキストを取り出すには、[`decodeMsg`](/docs/react-native/api/strings/msg) を使用します。 ```tsx import { decodeMsg } from 'gt-react-native'; const encoded = msg('Hello, world!'); const original = decodeMsg(encoded); // "Hello, world!" (元の文字列) const translated = m(encoded); // "Hello, world!" (ユーザーの言語) // ログやデバッグに便利 console.log('Original string:', decodeMsg(encoded)); console.log('Translated string:', m(encoded)); ``` ### decodeMsgの用途 * **開発とデバッグ**: 問題の切り分けのために元の文字列をログ出力する * **フォールバック処理**: 翻訳に失敗したときは元のテキストを使う * **文字列の比較**: 既知の元の値と比較する * **アナリティクス**: 元の文字列の使用状況を追跡する ```tsx // 例: フォールバック処理 function getDisplayText(encodedStr) { const m = useMessages(); try { return m(encodedStr); } catch (error) { console.warn('翻訳に失敗しました。元の文字列を使用します:', decodeMsg(encodedStr)); return decodeMsg(encodedStr); } } ``` ## 変数の使用 動的な内容を含む文字列では、プレースホルダーを使って変数を渡します: ```tsx // 変数付きの文字列をマークする const items = 100; export const pricing = [ { name: 'Basic', price: 100, description: msg('The basic plan includes {items} items', { items }) } ]; ``` ```tsx // コンポーネントで使用 function PricingCard() { const m = useMessages(); return (

{pricing[0].name}

{m(pricing[0].description)}

); } ``` ### ICU メッセージフォーマット 高度なフォーマットには、ICU 構文を使用します。 ```tsx const count = 10; const message = msg('There are {count, plural, =0 {no items} =1 {one item} other {{count} items}} in the cart', { count }); ``` ICU Message Format について詳しくは、[Unicode のドキュメント](https://unicode-org.github.io/icu/userguide/format_parse/messages/)を参照してください。 ## 例 ### ナビゲーション設定 ```tsx // config/navigation.ts import { msg } from 'gt-react-native'; export const mainNav = [ { label: msg('Home'), href: '/', icon: 'home' }, { label: msg('Products'), href: '/products', icon: 'package' }, { label: msg('About Us'), href: '/about', icon: 'info' } ]; export const footerLinks = [ { title: msg('Company'), links: [ { label: msg('About'), href: '/about' }, { label: msg('Careers'), href: '/careers' }, { label: msg('Contact'), href: '/contact' } ] }, { title: msg('Support'), links: [ { label: msg('Help Center'), href: '/help' }, { label: msg('Documentation'), href: '/docs' }, { label: msg('API Reference'), href: '/api' } ] } ]; ``` ```tsx // components/Navigation.tsx import { useMessages } from 'gt-react-native'; import { mainNav } from '../config/navigation'; function Navigation() { const m = useMessages(); return ( ); } ``` ### フォームの設定 ```tsx // config/forms.ts import { msg } from 'gt-react-native'; export const formMessages = { placeholders: { email: msg('Enter your email address'), password: msg('Enter your password'), message: msg('Type your message here...') }, actions: { send: msg('Send Message'), save: msg('Save Changes'), cancel: msg('Cancel') }, validation: { required: msg('This field is required'), email: msg('Please enter a valid email address'), minLength: msg('Must be at least {min} characters', { min: 8 }), maxLength: msg('Cannot exceed {max} characters', { max: 100 }) }, success: { saved: msg('Changes saved successfully'), sent: msg('Message sent successfully'), updated: msg('Profile updated') }, errors: { network: msg('Network error - please try again'), server: msg('Server error - please contact support'), timeout: msg('Request timed out - please try again') } }; ``` ```tsx // components/ContactForm.tsx import { useMessages } from 'gt-react-native'; import { formMessages } from '../config/forms'; function ContactForm() { const m = useMessages(); const [errors, setErrors] = useState({}); return (
{errors.email && {m(formMessages.validation.email)}}
); } ``` ### 動的コンテンツの生成 ```tsx // utils/productData.ts import { msg } from 'gt-react-native'; function mockProducts() { return [ { name: 'iPhone 15', company: 'Apple', category: 'Electronics' }, { name: 'Galaxy S24', company: 'Samsung', category: 'Electronics' } ]; } export function getProductData() { const products = mockProducts(); return products.map(product => ({ ...product, description: msg('{name} is a {category} product by {company}', { name: product.name, category: product.category, company: product.company }) })); } ``` ```tsx // components/ProductList.tsx import { useMessages } from 'gt-react-native'; import { getProductData } from '../utils/productData'; function ProductList() { const m = useMessages(); const products = getProductData(); return (
{products.map(product => (

{product.name}

{m(product.description)}

))}
); } ``` ## よくある問題 ### エンコード済み文字列を直接使用する [`msg`](/docs/react-native/api/strings/msg) の出力を直接使用しないでください。 ```tsx // ❌ 誤り - エンコードされた文字列を直接使用 const encoded = msg('Hello, world!'); return
{encoded}
; // エンコードされた文字列が表示され、翻訳は表示されない // ✅ 正しい - 先に文字列をデコードする const encoded = msg('Hello, world!'); const m = useMessages(); return
{m(encoded)}
; // 正しい翻訳が表示される ``` ### msg() 内の動的なコンテンツ 文字列はビルド時点で確定している必要があります: ```tsx // ❌ 誤り - 動的テンプレートリテラル const name = 'John'; const message = msg(`Hello, ${name}`); // ビルド時エラー // ✅ 正しい - 変数を使用する const name = 'John'; const message = msg('Hello, {name}', { name }); ``` ### デコード忘れ [`msg`](/docs/react-native/api/strings/msg) 文字列はすべてデコードする必要があります。 ```tsx // ❌ デコードが抜けている const config = { title: msg('Dashboard'), subtitle: msg('Welcome back') }; // コンポーネント内で後から使用する際にデコードを忘れた return

{config.title}

; // エンコードされた文字列が表示される // ✅ 正しい方法 - 使用時にデコードする const m = useMessages(); return

{m(config.title)}

; // 翻訳されたタイトルが表示される ``` ## 次のステップ * [辞書ガイド](/docs/react-native/guides/dictionaries) - 構造化データで翻訳を整理する * [言語ガイド](/docs/react-native/guides/languages) - サポートする言語を設定する * API リファレンス: * [`msg` 関数](/docs/react-native/api/strings/msg)